home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / GrowBoxDock / Sources / SimpleText.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  145.1 KB  |  5,222 lines

  1. /*
  2.     File:        SimpleText.c
  3.  
  4.     Contains:    SimpleText - a simple document editing application 
  5.  
  6.     Version:    Mac OS X
  7.  
  8.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  9.                 ("Apple") in consideration of your agreement to the following terms, and your
  10.                 use, installation, modification or redistribution of this Apple software
  11.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  12.                 please do not use, install, modify or redistribute this Apple software.
  13.  
  14.                 In consideration of your agreement to abide by the following terms, and subject
  15.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  16.                 copyrights in this original Apple software (the "Apple Software"), to use,
  17.                 reproduce, modify and redistribute the Apple Software, with or without
  18.                 modifications, in source and/or binary forms; provided that if you redistribute
  19.                 the Apple Software in its entirety and without modifications, you must retain
  20.                 this notice and the following text and disclaimers in all such redistributions of
  21.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  22.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  23.                 Apple Software without specific prior written permission from Apple.  Except as
  24.                 expressly stated in this notice, no other rights or licenses, express or implied,
  25.                 are granted by Apple herein, including but not limited to any patent rights that
  26.                 may be infringed by your derivative works or by other works in which the Apple
  27.                 Software may be incorporated.
  28.  
  29.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  30.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  31.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  32.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  33.                 COMBINATION WITH YOUR PRODUCTS.
  34.  
  35.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  36.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  37.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  39.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  40.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  41.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  
  43.     Copyright © 1993-2001 Apple Computer, Inc., All Rights Reserved
  44. */
  45.  
  46. #define MOUSE_WHEEL_SUPPORT 1
  47. #define PM_USE_SESSION_APIS 0
  48.  
  49. #include "MacIncludes.h"
  50.  
  51. #define CompilingMain 1
  52.  
  53. #include "SimpleText.h"
  54. #include "Clipboard.h"
  55.  
  56. #define qSingleSelectionOnly 0
  57.  
  58. // amount of time we leave a menu title hilited after a cmd key is used
  59. #define kMenuHiliteDelay 2
  60.  
  61. #define ff(x)        ((Fixed)(x) << 16)
  62.  
  63. #include <ApplicationServices/ApplicationServices.h>
  64. #include "/Users/river/Documents/keith/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/PrivateHeaders/CGSWindow.h"
  65.  
  66. typedef struct WIN  {
  67.     CGSWindowID    winID;
  68.     CGRect    winRect;
  69.     Boolean    isBouncing;
  70. } KnownWindow;
  71.  
  72. // --------------------------------------------------------------------------------------------------------------
  73. // FORWARD DECLARES
  74. // --------------------------------------------------------------------------------------------------------------
  75. void    UnhiliteMenuDelayed(unsigned long keyTime);
  76. OSStatus     DoActivate(WindowPtr pWindow, Boolean activating);
  77. OSStatus    DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime);
  78. OSStatus    DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls);
  79. Boolean CommandToIDs(short commandID, short * menuID, short *itemID);
  80. Boolean    AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn);
  81.  
  82. static Boolean CloseAllWindows( Boolean discard );
  83.  
  84. static void SynchronizeFiles( void );
  85.  
  86. #if MOUSE_WHEEL_SUPPORT
  87. static EventHandlerUPP        GetMouseWheelHandler();
  88. static OSStatus                MouseWheelHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* userData );
  89. #endif
  90.  
  91. // --------------------------------------------------------------------------------------------------------------
  92. // GLOBAL VARIABLES
  93. // --------------------------------------------------------------------------------------------------------------
  94. EventRecord            gEvent;                    // currently pending event
  95. Boolean                gAllDone;                // true if the application is the in process of terminating
  96. MachineInfoRec        gMachineInfo;            // info about abilities and options installed on this machine
  97. short                gApplicationResFile;    // resource fork of application
  98. RgnHandle            gCursorRgn;                // region to control the cursor apearence
  99. #if CALL_NOT_IN_CARBON
  100. AGRefNum            gAGRefNum = -1;            // AppleGuide database which is open
  101. FSSpec                gAGSpec;                // where to find our database
  102. AGCoachRefNum        gAGCoachRefNum = -1;    // coach handler refNum
  103. ThreadID            gAGThread;                // thread that looks for AppleGuide database
  104. #endif
  105. ThreadID            gFontThread;            // thread that builds font menu
  106. ThreadID            gStarterThread;            // starts our other threads for us
  107. Boolean                gDontYield;                // whether our threads should yield
  108. void*                gThreadResults;            // scratch space for thread results
  109. ComponentInstance        gOSAComponent = NULL;        // for AppleScript: connection to OSA scripting component
  110.  
  111. // AEC, addded
  112. ControlActionUPP    gVActionProc = NULL;
  113. ControlActionUPP    gHActionProc = NULL;
  114.  
  115. // These variables are for the find/replace commands
  116. Str255            gFindString = "\p", gReplaceString = "\p";
  117. Boolean            gWrapAround = false, gCaseSensitive = false;
  118.  
  119. // Added these variables to get scrolling to happen on a delayed and accelerated curve
  120. long            gVScrollTrackStartTicks = 0L;        // Holds starting value when scroll action began
  121. #define            kVScrollAcceleratorIncrement  1L
  122. long            gVScrollAccelerator = kVScrollAcceleratorIncrement;            // Value of accelerator incremented at each scroll call
  123. const    long    kScrollAccelerateDelay = 30L;        // Number of ticks to delay until beginning acceleration
  124. const     long    kScrollAccelerateLag = 40L;            // Number of ticks to delay until next bump in acceleration
  125.  
  126. // A hack to allow kScrollBarSize to continue working in all the files, but
  127. // still letting us use theme metrics
  128. SInt16            kScrollBarSize;
  129.  
  130.  
  131. // Metrowerks MWCRuntime.lib defines qd for us on PPC, and their
  132. // __runtime module does under the 68K case. OTOH, neither SC nor
  133. // MrC give us qd for free, so we need it there. I'm still not
  134. // certain which way to go for the ThinkC or Symantec PPC case.
  135. #if !defined(__MWERKS__)
  136. // QuickDraw globals
  137. //QDGlobals        qd;
  138. #endif
  139.  
  140. // --------------------------------------------------------------------------------------------------------------
  141. #if 0
  142. static pascal Boolean AlertFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  143. {
  144.     if (theEvent->what == activateEvt && (DialogPtr) theEvent->message == theDialog)
  145.         {
  146.         SetDialogDefaultItem(theDialog, 1);
  147.         }
  148.  
  149.     if (StdFilterProc(theDialog, theEvent, itemHit))
  150.         return true;
  151.  
  152.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  153.     // drastically changing how the system handles the menu bar during our alert)
  154.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  155.         {
  156.         HandleEvent(theEvent);
  157.         }
  158.  
  159.     return false;
  160.  
  161. } // AlertFilter
  162. #endif
  163.  
  164. void ConductErrorDialog(OSStatus error, short commandID, short alertType)
  165. {
  166.     long        foundError;            // The error, converted to a number
  167.     short        stringIndex;        // Index into the strings
  168.     Str255        errorText;            // the error in a string format
  169.     
  170.     // Start with no error so far
  171.     foundError = 0;
  172.     
  173.     // Start with the first string
  174.     stringIndex = 1;
  175.     
  176.     // Loop until we find an error string
  177.     errorText[0] = 0;
  178.  
  179.     do
  180.         {
  181.         // Get the string, and convert it to a number
  182.         GetIndString(errorText, kErrorBaseID + commandID, stringIndex);
  183.         if (errorText[0] == 0)
  184.             break;
  185.         StringToNum(errorText, &foundError);
  186.         
  187.         // If we reach the last string, or we match the error code
  188.         if ((foundError == 0) ||
  189.             (foundError == error))
  190.             {
  191.             // Get the text string for this error
  192.             GetIndString(errorText, kErrorBaseID + commandID, stringIndex+1);
  193.             }
  194.         else
  195.             {
  196.             // Otherwise, make us continue until we get a string
  197.             errorText[0] = 0;
  198.             }
  199.             
  200.         // Advance so we get the next string number
  201.         stringIndex += 2;
  202.         
  203.         } while (errorText[0] == 0);                // errorText[0] == 0
  204.         
  205.     if (errorText[0] != 0)
  206.         {
  207.         DialogPtr    dPtr;
  208.         short        hit;
  209.         Cursor        arrow;
  210.         
  211.         SetCursor(GetQDGlobalsArrow(&arrow));
  212.         ParamText(errorText, "\p", "\p", "\p");
  213.         
  214.         dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowPtr)-1);
  215.         
  216.         SetDialogDefaultItem(dPtr, ok);
  217.         
  218.         BeginMovableModal();
  219.         
  220.         do
  221.             {
  222.             MovableModalDialog(nil, &hit);
  223.             } while (hit != ok);
  224.             
  225.         DisposeDialog(dPtr);
  226.         EndMovableModal();
  227.         }
  228.         
  229. } // ConductErrorDialog
  230.  
  231. // --------------------------------------------------------------------------------------------------------------
  232. static void MovableModalMenus(DialogPtr dPtr, short *pItem, long menuResult, long keyTime)
  233. {
  234.     short    iCut, iCopy, iClear, iPaste;
  235.     short    editMenu;
  236.     short    menuItem = menuResult & 0xFFFF;
  237.     
  238.     // find out where edit menus are
  239.     CommandToIDs(cCut, &editMenu, &iCut);
  240.     CommandToIDs(cCopy, &editMenu, &iCopy);
  241.     CommandToIDs(cClear, &editMenu, &iClear);
  242.     CommandToIDs(cPaste, &editMenu, &iPaste);
  243.     
  244.     UnhiliteMenuDelayed(keyTime);
  245.     switch (menuResult >> 16)
  246.         {
  247.         case mApple:
  248.             {
  249. #if(0)
  250.             Str255    tempString;
  251.             
  252.             GetMenuItemText(GetMenuHandle(menuResult>>16), menuItem, tempString);
  253.             OpenDeskAcc(tempString);
  254. #endif            
  255.             }
  256.             break;
  257.         case mEdit:
  258.             {
  259.             short    type;
  260.             Handle    item;
  261.             Rect    box;
  262.             short    editField = GetDialogKeyboardFocusItem(dPtr);
  263.             
  264.             // return typed item, if it isn't disabled
  265.             GetDialogItem(dPtr, editField, &type, &item, &box);
  266.             if ((type & itemDisable) == 0)
  267.                 *pItem = editField;
  268.                 
  269.             if (menuItem == iCut)
  270.                 {
  271.                 DialogCut(dPtr);
  272.                 ClearCurrentScrap();
  273.                 TEToScrap();
  274.                 }
  275.                 
  276.             if (menuItem == iCopy)
  277.                 {
  278.                 DialogCopy(dPtr);
  279.                 ClearCurrentScrap();
  280.                 TEToScrap();
  281.                 }
  282.                 
  283.             if (menuItem == iClear)
  284.                 DialogDelete(dPtr);
  285.                 
  286.             if (menuItem == iPaste)
  287.                 DialogPaste(dPtr);
  288.             }
  289.             break;
  290.         }
  291.         
  292. } // MovableModalMenus
  293.  
  294. // --------------------------------------------------------------------------------------------------------------
  295. void UnhiliteMenuDelayed(unsigned long keyTime)
  296. {
  297.     if (keyTime != 0)
  298.         {
  299.         keyTime = TickCount() - keyTime;
  300.         if (keyTime < kMenuHiliteDelay)
  301.             Delay(kMenuHiliteDelay - keyTime, &keyTime);
  302.         }
  303.     HiliteMenu(0);
  304. }
  305.  
  306. // --------------------------------------------------------------------------------------------------------------
  307. void MovableModalDialog(ModalFilterProcPtr filterProc, short *pItem)
  308. /*
  309.     Call this as you would ModalDialog, when the dialog is moveable
  310.     modal.
  311.     
  312.     However, first call BeginMovableModal, and afterwards (after
  313.     disposing of dialog) call EndMovableModal.
  314. */
  315. {
  316.     GrafPtr     curPort;
  317.     DialogPtr    dPtr = GetDialogFromWindow( FrontNonFloatingWindow() /*FrontWindow()*/);
  318.     RgnHandle    structRegion;
  319.  
  320.     *pItem = 0;
  321.     
  322.     if (dPtr)
  323.         {
  324.         GetPort(&curPort);
  325.                 SetPort(GetWindowPort(FrontWindow()));
  326.         
  327.         do
  328.             {
  329.             WaitNextEvent(mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask,
  330.                             &gEvent, 0, nil);
  331.             
  332.             // call the filter proc
  333.             if ( (filterProc) && ((*filterProc) (dPtr, &gEvent, pItem)) )
  334.                 break;
  335.                             
  336.             // call the basic filtering
  337.             if (StdFilterProc(dPtr, &gEvent, pItem))
  338.                 break;
  339.                 
  340.             // handle keyboard
  341.             if ((gEvent.what == keyDown || gEvent.what == autoKey) && (gEvent.modifiers & cmdKey))
  342.                 {
  343.                 long    result;
  344.                 long    tck;
  345.                 
  346.                 result = MenuKey(gEvent.message & charCodeMask);
  347.                 tck = TickCount();
  348.                 
  349.                 MovableModalMenus(dPtr, pItem, result, tck);
  350.                 break;
  351.                 }
  352.                 
  353.             // handle clicks and drags
  354.             if (gEvent.what == mouseDown)
  355.                 {
  356.                 WindowPtr    whichWindow;
  357.                 short        part = FindWindow(gEvent.where, &whichWindow);
  358.                 DialogPtr    whichDialog = NULL;
  359.                 
  360.                 if (whichWindow)
  361.                     whichDialog = GetDialogFromWindow(whichWindow);
  362.  
  363.                 // menu bar events
  364.                 if (part == inMenuBar)
  365.                     {
  366.                     InitCursor();    // make sure we've got an arrow during menu tracking
  367.                     MovableModalMenus(dPtr, pItem, MenuSelect(gEvent.where), 0);
  368.                     break;
  369.                     }
  370.                     
  371.                 structRegion = NewRgn();
  372.                 // check for outside of our window
  373.                 GetWindowRegion( GetDialogWindow( dPtr ), kWindowStructureRgn, structRegion );
  374.                 if (!PtInRgn(gEvent.where, structRegion))
  375.                     {
  376.                     SysBeep(1);
  377.                     gEvent.what = nullEvent;
  378.                     }
  379.                 DisposeRgn( structRegion );
  380.                     
  381.                 // drag the window around
  382.                                 if ( (part == inDrag) && (whichDialog == dPtr) )
  383.                     {
  384.                     Rect    tempRect;
  385.                     
  386.                     DragWindow(whichWindow, gEvent.where, GetRegionBounds( GetGrayRgn(), &tempRect) );
  387.                     gEvent.what = nullEvent;
  388.                     }
  389.                 }
  390.                 
  391.             // check with standard dialog stuff    
  392.             {
  393.             DialogPtr    tempDialog;
  394.             
  395.             if ( IsDialogEvent(&gEvent) && DialogSelect(&gEvent, &tempDialog, pItem) )
  396.                 break;
  397.             }
  398.             
  399.             // handle updates
  400.             if (gEvent.what == updateEvt)
  401.                 {
  402.                 HandleEvent(&gEvent);
  403.                 break;
  404.                 }
  405.             } while (true);
  406.         
  407.         SetPort(curPort);
  408.         }
  409.         
  410. } // MovableModalDialog
  411.  
  412. // --------------------------------------------------------------------------------------------------------------
  413. void BeginMovableModal(void)
  414. {
  415.     DialogPtr    dPtr = GetDialogFromWindow(FrontWindow());
  416.     WindowPtr    nextWindow = GetNextWindow(FrontWindow());
  417.     
  418.     // Disable the current indicator because the upcoming dialog is moveable modal
  419.     HiliteMenu(0);
  420.         
  421.     if (nextWindow)
  422.         DoActivate(nextWindow, false);
  423.     AdjustMenus(GetDialogWindow(dPtr), (GetDialogKeyboardFocusItem(dPtr) > 0), false);
  424.  
  425. } // BeginMovableModal
  426.  
  427. // --------------------------------------------------------------------------------------------------------------
  428. void EndMovableModal(void)
  429. {
  430.     WindowPtr    nextWindow = FrontWindow();
  431.     
  432.     AdjustMenus(nextWindow, true, false);
  433.     if (nextWindow)
  434.         DoActivate(nextWindow, true);
  435.     
  436. } // EndMovableModal
  437.  
  438. // --------------------------------------------------------------------------------------------------------------
  439. short ConductFindOrReplaceDialog(short dialogID)
  440. {
  441.     DialogPtr    dPtr;
  442.     short        hit;
  443.     
  444.     // menu shouldn't stay hilighted during the dialog
  445.     HiliteMenu(0);
  446.     
  447.     dPtr = GetNewDialog(dialogID, nil, (WindowPtr)-1);
  448.     if (dPtr)
  449.         {
  450.         short    kind;
  451.         Rect    box;
  452.         Handle    item;
  453.         
  454.         // standard default behavior
  455.         SetDialogDefaultItem(dPtr, ok);
  456.         SetDialogCancelItem (dPtr, cancel);
  457.         SetDialogTracksCursor(dPtr, true);
  458.         
  459.         // Find string
  460.         GetDialogItem(dPtr, iFindEdit, &kind, &item, &box);
  461.         SetDialogItemText(item, gFindString);
  462.  
  463.         // check boxes
  464.         GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box);
  465.         SetControlValue((ControlHandle)item, gCaseSensitive);
  466.         GetDialogItem(dPtr, iWrapAround, &kind, &item, &box);
  467.         SetControlValue((ControlHandle)item, gWrapAround);
  468.         
  469.         if (dialogID == kReplaceWindowID)
  470.             {
  471.             // Replace string
  472.             GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box);
  473.             SetDialogItemText(item, gReplaceString);
  474.             }
  475.         
  476.         // select the search text by default
  477.         SelectDialogItemText(dPtr, iFindEdit, 0, 32767);
  478.         
  479.         // and away we go!
  480.         ShowWindow(GetDialogWindow(dPtr));
  481.         BeginMovableModal();
  482.         
  483.         do
  484.             {
  485.             MovableModalDialog(nil, &hit);
  486.             switch (hit)
  487.                 {
  488.                 case iCaseSensitive:
  489.                 case iWrapAround:
  490.                     GetDialogItem(dPtr, hit, &kind, &item, &box);
  491.                     SetControlValue((ControlHandle)item, 1-GetControlValue((ControlHandle)item));
  492.                     break;
  493.                 }
  494.             } while ( (hit != ok) && (hit != cancel) && (hit != iReplaceAll) );
  495.         
  496.         if (hit != cancel)
  497.             {
  498.             // Find string
  499.             GetDialogItem(dPtr, iFindEdit, &kind, &item, &box);
  500.             GetDialogItemText(item, gFindString);
  501.     
  502.             // nothing to find is like a cancel
  503.             if (gFindString[0] < 1)
  504.                 hit = cancel;
  505.                 
  506.             // check boxes
  507.             GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box);
  508.             gCaseSensitive = GetControlValue((ControlHandle)item);
  509.             GetDialogItem(dPtr, iWrapAround, &kind, &item, &box);
  510.             gWrapAround = GetControlValue((ControlHandle)item);
  511.             
  512.             if (dialogID == kReplaceWindowID)
  513.                 {
  514.                 // Replace string
  515.                 GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box);
  516.                 GetDialogItemText(item, gReplaceString);
  517.                 }
  518.             }
  519.             
  520.         DisposeDialog(dPtr);
  521.         EndMovableModal();
  522.         }
  523.         
  524.     return(hit);
  525.     
  526. } // ConductFindOrReplaceDialog
  527.  
  528. // --------------------------------------------------------------------------------------------------------------
  529. void LocalToGlobalRgn(RgnHandle rgn)
  530. {
  531.     Point        offset;
  532.     CGrafPtr    thePort = GetQDGlobalsThePort();
  533.     Rect bounds;
  534.  
  535.     GetPortBounds(thePort, &bounds);
  536.     offset = TopLeft(bounds);
  537.         
  538.     OffsetRgn(rgn, -offset.h, -offset.v);
  539.     
  540. } // LocalToGlobalRgn
  541.  
  542. // --------------------------------------------------------------------------------------------------------------
  543. void GlobalToLocalRgn(RgnHandle rgn)
  544. {
  545.     Point        offset;
  546.     CGrafPtr    thePort = GetQDGlobalsThePort();
  547.     Rect bounds;
  548.  
  549.     GetPortBounds(thePort, &bounds);
  550.  
  551.     offset = TopLeft(bounds);
  552.         
  553.     OffsetRgn(rgn, offset.h, offset.v);
  554.     
  555. } // GlobalToLocalRgn
  556.  
  557. // --------------------------------------------------------------------------------------------------------------
  558. void SetWatchCursor(void)
  559. {
  560.     CursHandle    theWatch;
  561.         
  562.     theWatch = MacGetCursor(watchCursor);
  563.     if (theWatch)
  564.         {
  565.         char    oldState;
  566.         
  567.         oldState = HGetState((Handle) theWatch);
  568.         HLock((Handle) theWatch);
  569.         SetCursor(*theWatch);
  570.         HSetState((Handle) theWatch, oldState);
  571.         }
  572.         
  573. } // SetWatchCursor
  574.  
  575. // --------------------------------------------------------------------------------------------------------------
  576. void LongRectToRect(LongRect* longRect, Rect *rect)
  577. {
  578.     rect->top         = longRect->top;
  579.     rect->left         = longRect->left;
  580.     rect->bottom     = longRect->bottom;
  581.     rect->right     = longRect->right;
  582.     
  583. } // LongRectToRect
  584.  
  585. // --------------------------------------------------------------------------------------------------------------
  586. void RectToLongRect(Rect *rect, LongRect *longRect)
  587. {
  588.     longRect->top         = rect->top;
  589.     longRect->left         = rect->left;
  590.     longRect->bottom     = rect->bottom;
  591.     longRect->right     = rect->right;
  592.     
  593. } // RectToLongRect
  594.  
  595. // --------------------------------------------------------------------------------------------------------------
  596. void GetPICTRectangleAt72dpi(PicHandle hPicture, Rect *pictureRect)
  597. {
  598.     typedef struct FixedRect {
  599.         Fixed left;
  600.         Fixed top;
  601.         Fixed right;
  602.         Fixed bottom;
  603.     } FixedRect;
  604.     
  605.     typedef struct {
  606.         Picture                pictInfo;
  607.         unsigned short        versionOp;        // 0x1101
  608.         Byte                opCodes[1];
  609.     } PICTHeaderVer1;
  610.     
  611.     typedef struct {
  612.         Picture            pictInfo;
  613.         unsigned short    versionOp;        // 0x0011
  614.         unsigned short    versionOp2;        // 0x02ff
  615.         unsigned short    headerOp;        // 0x0c00
  616.         unsigned short    version;        // 0xffff
  617.         unsigned short    version2;        // 0xffff
  618.         FixedRect        pictBounds;
  619.         unsigned long    reserved;
  620.         unsigned short    opCodes[1];
  621.     } PICTHeaderVer2;
  622.     
  623.     typedef struct {
  624.         Picture            pictInfo;
  625.         unsigned short    versionOp;        // 0x0011
  626.         unsigned short    versionOp2;        // 0x02ff
  627.         unsigned short    headerOp;        // 0x0c00
  628.         unsigned short    version;        // 0xfffe
  629.         unsigned short    reserved;        // 0x0000
  630.         Fixed            hRes;
  631.         Fixed            vRes;
  632.         Rect            pictBounds;
  633.         unsigned long    reserved2;
  634.         unsigned short    opCodes[1];
  635.     } PICTHeaderVer2Ext;
  636.  
  637.     Fixed            hRes, vRes;
  638.     PICTHeaderVer1* pPict = (PICTHeaderVer1*) *hPicture;
  639.     Rect            srcRect = (**hPicture).picFrame;
  640.  
  641.     hRes = vRes = ff(72);        // assume 72 dpi
  642.  
  643.     if (pPict->versionOp == 0x0011) 
  644.         {    
  645.         // Version 2 PICT
  646.     
  647.         PICTHeaderVer2* pPict2 = (PICTHeaderVer2*) pPict;
  648.         
  649.         if (pPict2->version == 0xfffe) 
  650.             {    
  651.             // Extended Version 2
  652.             PICTHeaderVer2Ext* pPict2ext = (PICTHeaderVer2Ext*) pPict;
  653.             hRes = pPict2ext->hRes;
  654.             vRes = pPict2ext->vRes;
  655.             srcRect = pPict2ext->pictBounds;
  656.             }
  657.         }
  658.  
  659.     hRes = FixDiv(hRes, ff(72));
  660.     vRes = FixDiv(vRes, ff(72));
  661.     pictureRect->left     = Fix2Long(FixDiv( ff(srcRect.left),     hRes ));
  662.     pictureRect->right     = Fix2Long(FixDiv( ff(srcRect.right),     hRes ));
  663.     pictureRect->top     = Fix2Long(FixDiv( ff(srcRect.top),     vRes ));
  664.     pictureRect->bottom = Fix2Long(FixDiv( ff(srcRect.bottom),     vRes ));
  665.     
  666. } // GetPICTRectangleAt72dpi
  667.  
  668. // --------------------------------------------------------------------------------------------------------------
  669. static WindowDataPtr    GetWindowInfo(WindowPtr pWindow)
  670. {
  671.     WindowDataPtr result = nil;
  672.     
  673.     if     (
  674.         (pWindow) &&
  675.         (GetWindowKind(pWindow) == userKind)
  676.         )
  677.         result = (WindowDataPtr) GetWRefCon(pWindow);
  678.  
  679.     return result;
  680.     
  681. } // GetWindowInfo
  682.  
  683. // --------------------------------------------------------------------------------------------------------------
  684. static short ZeroStringSub(Str255 destString, Str255 subStr)
  685.     // returns number of substitutions performed
  686. {
  687.     OSStatus    anErr;
  688.     Handle    destHandle = nil;
  689.     Handle    subHandle = nil;
  690.     short    count = 0;
  691.  
  692.     anErr = PtrToHand(&destString[1], &destHandle, destString[0]);
  693.     if (anErr == noErr)
  694.         {        
  695.         anErr = PtrToHand(&subStr[1], &subHandle, subStr[0]);
  696.         if (anErr == noErr)
  697.             {
  698.             count = ReplaceText(destHandle, subHandle, "\p^0");        // error or # of substitutions
  699.                         
  700.             destString[0] = GetHandleSize(destHandle);
  701.             BlockMoveData(*destHandle, &destString[1], destString[0]);
  702.             }
  703.         }
  704.  
  705.     DisposeHandle(destHandle);
  706.     DisposeHandle(subHandle);
  707.  
  708.     if (count < 0)
  709.         count = 0;        // change error code into count = 0 substitutions
  710.  
  711.     return count;
  712.  
  713. } // ZeroStringSub
  714.  
  715. // --------------------------------------------------------------------------------------------------------------
  716. // BEGIN SCROLL ACTION PROCS
  717. // --------------------------------------------------------------------------------------------------------------
  718. void SetControlAndClipAmount(ControlHandle control, short * amount)
  719. {
  720.     short        value, max;
  721.     
  722.     value = GetControlValue(control);    /* get current value */
  723.     max = GetControlMaximum(control);        /* and maximum value */
  724.     *amount = value - *amount;
  725.     if ( *amount < 0 )
  726.     {
  727.         *amount = 0;
  728.         gVScrollAccelerator = kVScrollAcceleratorIncrement;
  729.     }
  730.     else
  731.         {
  732.             if ( *amount > max )
  733.             {
  734.                 *amount = max;
  735.                 gVScrollAccelerator = kVScrollAcceleratorIncrement;
  736.             }
  737.         }
  738.     SetControlValue(control, *amount);
  739.     *amount = value - *amount;        /* calculate the real change */
  740.     
  741. } // SetControlAndClipAmount
  742.  
  743. // --------------------------------------------------------------------------------------------------------------
  744. static pascal void VActionProc(ControlHandle control, short part)
  745. {
  746.     if (part != 0)
  747.         {
  748.                 WindowPtr        pWindow = GetControlOwner(control);
  749.         WindowDataPtr         pData = GetWindowInfo(pWindow);
  750.         short            amount = 0;
  751.         
  752.         switch (part)
  753.             {
  754.             case kControlUpButtonPart:
  755.                 if (gVScrollAccelerator > kVScrollAcceleratorIncrement) // We're already in accellerated mode
  756.                 {
  757.                     //Only increment the accelerator if it's been longer than the lag time. Then reset the timer
  758.                     if (TickCount() > (gVScrollTrackStartTicks + kScrollAccelerateLag)) 
  759.                     {
  760.                         gVScrollAccelerator += kVScrollAcceleratorIncrement;
  761.                         gVScrollTrackStartTicks = TickCount();
  762.                     }    
  763.                 }else // We haven't started acceleration yet
  764.                 {
  765.                     if (TickCount() > (gVScrollTrackStartTicks + kScrollAccelerateDelay))
  766.                     {    
  767.                         gVScrollAccelerator += kVScrollAcceleratorIncrement; // start acceleration
  768.                         gVScrollTrackStartTicks = TickCount();                  // reset the timer to start our lag acceleration
  769.                     }
  770.                 }
  771.                 amount = pData->vScrollAmount * gVScrollAccelerator;
  772.                 //printf("Scroll Amount: %d Scrolling Accelerator: %ld Will Scroll By: %d\r\n", pData->vScrollAmount, gVScrollAccelerator, amount);
  773.                 SetControlAndClipAmount(control, &amount);
  774.                 break;
  775.                 
  776.             case kControlDownButtonPart:
  777.                 if (gVScrollAccelerator > kVScrollAcceleratorIncrement) // We're already in accellerated mode
  778.                 {
  779.                     //Only increment the accelerator if it's been longer than the lag time. Then reset the timer
  780.                     if (TickCount() > (gVScrollTrackStartTicks + kScrollAccelerateLag)) 
  781.                     {
  782.                         gVScrollAccelerator += kVScrollAcceleratorIncrement;
  783.                         gVScrollTrackStartTicks = TickCount();
  784.                     }    
  785.                 }else // We haven't started acceleration yet
  786.                 {
  787.                     if (TickCount() > (gVScrollTrackStartTicks + kScrollAccelerateDelay))
  788.                     {    
  789.                         gVScrollAccelerator += kVScrollAcceleratorIncrement; // start acceleration
  790.                         gVScrollTrackStartTicks = TickCount();                  // reset the timer to start our lag acceleration
  791.                     }
  792.                 }
  793.                 amount = -pData->vScrollAmount * gVScrollAccelerator;
  794.                 //printf("Scroll Amount: %d Scrolling Accelerator: %ld Will Scroll By: %d\r\n", pData->vScrollAmount, gVScrollAccelerator, amount);
  795.                 SetControlAndClipAmount(control, &amount);
  796.                 break;
  797.                 
  798.             // vertical page scrolling should be a multiple of the incremental scrolling -- so that
  799.             // we avoid half-lines of text at the bottom of pages.
  800.             
  801.             // More generically, if there was a method for dealing with text scrolling by a non-constant
  802.             // amount, this would be better -- but SimpleText currently doesn't have a framework to allow
  803.             // the document object to override the scroll amount dynamically.  Maybe something to add in
  804.             // the future.
  805.             case kControlPageUpPart:
  806.                 amount = (((pData->contentRect.bottom - pData->contentRect.top) / pData->vScrollAmount)-1) * pData->vScrollAmount;
  807.                 if (amount == 0)
  808.                     amount = pData->contentRect.bottom - pData->contentRect.top;
  809.                 SetControlAndClipAmount(control, &amount);
  810.                 break;
  811.  
  812.             case kControlPageDownPart:
  813.                 amount = (((pData->contentRect.top - pData->contentRect.bottom) / pData->vScrollAmount)+1) * pData->vScrollAmount;
  814.                 if (amount == 0)
  815.                     amount = pData->contentRect.top - pData->contentRect.bottom;
  816.                 SetControlAndClipAmount(control, &amount);
  817.                 break;
  818.  
  819.             default:
  820.                 amount = pData->oldVValue - GetControlValue(control);
  821.                 pData->oldVValue = GetControlValue(control);
  822.                 break;
  823.             }
  824.         
  825.         DoScrollContent(pWindow, pData, 0, amount);
  826.         }
  827.         
  828. } // VActionProc
  829.  
  830.  
  831. // --------------------------------------------------------------------------------------------------------------
  832. static pascal void HActionProc(ControlHandle control, short part)
  833. {
  834.     if (part != 0)
  835.         {
  836.         WindowPtr        pWindow = GetControlOwner(control);
  837.         WindowDataPtr         pData = GetWindowInfo(pWindow);
  838.         short            amount = 0;
  839.         
  840.         switch (part)
  841.             {
  842.             case kControlUpButtonPart:
  843.                 amount = pData->hScrollAmount;
  844.                 SetControlAndClipAmount(control, &amount);
  845.                 break;
  846.                 
  847.             case kControlDownButtonPart:
  848.                 amount = -pData->hScrollAmount;
  849.                 SetControlAndClipAmount(control, &amount);
  850.                 break;
  851.                 
  852.             case kControlPageUpPart:
  853.                 amount = pData->contentRect.right - pData->contentRect.left;
  854.                 SetControlAndClipAmount(control, &amount);
  855.                 break;
  856.  
  857.             case kControlPageDownPart:
  858.                 amount = pData->contentRect.left - pData->contentRect.right;
  859.                 SetControlAndClipAmount(control, &amount);
  860.                 break;
  861.  
  862.             default:
  863.                 amount = pData->oldHValue - GetControlValue(control);
  864.                 pData->oldHValue = GetControlValue(control);
  865.                 break;
  866.             }
  867.         
  868.         DoScrollContent(pWindow, pData, amount, 0);
  869.         }
  870.         
  871. } // HActionProc
  872.  
  873.  
  874. // --------------------------------------------------------------------------------------------------------------
  875. // END SCROLL ACTION PROCS
  876. // --------------------------------------------------------------------------------------------------------------
  877.  
  878. // --------------------------------------------------------------------------------------------------------------
  879. // SEARCH/REPLACE UTILITY FUNCTIONS
  880. // --------------------------------------------------------------------------------------------------------------
  881. static Boolean IsThisTheString(
  882.             Ptr p,                        // pointer to check
  883.             Str255 searchString,        // string to check for
  884.             Boolean isCaseSensitive)    // case sensitive check or not
  885. /*
  886.     Returns true if the supplied string is at the specified offset.
  887.     Otherwise returns false.
  888. */
  889. {
  890.         Handle     itl2Table;
  891.         long    offset, length;
  892.         short    script;
  893.         Boolean result = false;
  894.  
  895.         script = FontToScript(GetSysFont());
  896.         GetIntlResourceTable(script, smWordSelectTable, &itl2Table, &offset, &length);
  897.  
  898.         if (itl2Table != NULL)
  899.         {
  900.                 if (isCaseSensitive)
  901.                     result = (CompareText(p, &searchString[1], searchString[0], searchString[0], itl2Table) == 0);
  902.                 else
  903.                     result = (IdenticalText(p, &searchString[1], searchString[0], searchString[0], itl2Table) == 0);
  904.         }
  905.  
  906.                 return result;
  907. } // IsThisTheString
  908.  
  909.  
  910. // --------------------------------------------------------------------------------------------------------------
  911.  
  912. Boolean PerformSearch(
  913.         Handle    h,                    // handle to search
  914.         long start,                    // offset to begin with
  915.         Str255 searchString,        // string to search for
  916.         Boolean isCaseSensitive,    // case sensitive search
  917.         Boolean isBackwards,        // search backwards from starting point
  918.         Boolean isWraparound,        // wrap search around from end->begining
  919.         long * pNewStart,            // returned new selection start
  920.         long * pNewEnd)                // returned new selection end
  921. /*
  922.     Performs a search on the supplied handle, starting at the provided
  923.     offset.  Returns the new selection start and end values, and true
  924.     if the search is successful.  Otherwise it returns false.
  925. */
  926. {
  927.     char    flags;
  928.     Ptr        startPtr;
  929.     Ptr        endPtr;
  930.     Ptr        searchPtr;
  931.     Boolean    foundIt = false;
  932.     
  933.     flags = HGetState(h);
  934.     HLock(h);
  935.             
  936.     // back up one when searching backwards, or we'll hit every time on the current
  937.     // character
  938.     if (isBackwards)
  939.         {
  940.         if (start != 0)
  941.             {
  942.             --start;
  943.             }
  944.         else
  945.             {
  946.             if (isWraparound)
  947.                 start = GetHandleSize(h);
  948.             else
  949.                 return(false);
  950.             }
  951.         }
  952.         
  953.     // determine the bounds of the searching
  954.     startPtr = (*h) + start;
  955.     if ( isWraparound )
  956.         {
  957.         if (isBackwards)
  958.             {
  959.             // go backwards until just after the start, or begining of
  960.             // document is start is the end
  961.             if (start == GetHandleSize(h))
  962.                 endPtr = *h;
  963.             else
  964.                 endPtr = startPtr + 1;
  965.             }
  966.         else
  967.             {
  968.             // go forwards until just before the start, or to the end
  969.             // of the document is the start is already the begining
  970.             if (start == 0)
  971.                 endPtr = *h + GetHandleSize(h);
  972.             else
  973.                 endPtr = startPtr - 1;
  974.             }
  975.         }
  976.     else
  977.         {
  978.         if (isBackwards)
  979.             {
  980.             // go back until hit begining of document
  981.             endPtr = *h-1;    
  982.             }
  983.         else
  984.             {
  985.             // go forward until hit end of document
  986.             endPtr = *h + GetHandleSize(h);
  987.             }
  988.         }
  989.         
  990.     searchPtr = startPtr;
  991.     while (searchPtr != endPtr)
  992.         {
  993.         short    byteType;
  994.         
  995.         byteType = CharacterByteType(startPtr, searchPtr - startPtr, smCurrentScript);
  996.         
  997.         if ( ((byteType == smSingleByte) || (byteType == smFirstByte)) &&
  998.             IsThisTheString(searchPtr, searchString, isCaseSensitive)
  999.             )
  1000.             {
  1001.             foundIt = true;
  1002.             *pNewStart = searchPtr - *h;
  1003.             *pNewEnd = *pNewStart + searchString[0];
  1004.             break;
  1005.             }
  1006.             
  1007.         if (isBackwards)
  1008.             --searchPtr;
  1009.         else
  1010.             ++searchPtr;
  1011.             
  1012.         if (isWraparound)
  1013.             {
  1014.             if (searchPtr < *h)
  1015.                 searchPtr = *h + GetHandleSize(h);
  1016.             if (searchPtr > *h + GetHandleSize(h))
  1017.                 searchPtr = *h;
  1018.             }
  1019.         }
  1020.         
  1021.     HSetState(h, flags);
  1022.     
  1023.     return(foundIt);
  1024.     
  1025. } // PerformSearch
  1026.  
  1027. // --------------------------------------------------------------------------------------------------------------
  1028. // SELECTION UTILITY ROUTINES
  1029. // --------------------------------------------------------------------------------------------------------------
  1030. void DrawSelection(WindowDataPtr pData, Rect *pSelection, short * pPhase, Boolean bumpPhase)
  1031. {
  1032.     if    (!EmptyRect(pSelection) ) 
  1033.         {
  1034.         RgnHandle    oldClip = NewRgn();
  1035.         Pattern        aPattern;
  1036.         Rect        newClip;
  1037.  
  1038.         
  1039.         if     ( 
  1040.             (bumpPhase) && 
  1041.             (MOVESELECTION(TickCount()) ) 
  1042.             )
  1043.             {
  1044.             if ((++(*pPhase)) > 7 )
  1045.                 *pPhase = 1;
  1046.             }
  1047.             
  1048.         // setup for drawing in this window
  1049.         SetPortWindowPort (pData->theWindow);
  1050.         GetClip(oldClip);
  1051.         PenMode(notPatXor);
  1052.         
  1053.         // offset the draw area (SetOrigin a must to preserve pattern appearence)
  1054.         // and the clip area to avoid stepping on the scroll bars
  1055.         SetOrigin(GetControlValue(pData->hScroll), GetControlValue(pData->vScroll));
  1056.         newClip = pData->contentRect;
  1057.         OffsetRect(&newClip, GetControlValue(pData->hScroll), GetControlValue(pData->vScroll));
  1058.         ClipRect(&newClip);
  1059.         
  1060.         // do the draw
  1061.         GetIndPattern(&aPattern, kPatternListID, (*pPhase)+1);
  1062.         PenPat(&aPattern);
  1063.         FrameRect(pSelection);
  1064.         SetOrigin(0, 0);
  1065.         
  1066.         // restore the old port settings
  1067.         SetClip(oldClip);
  1068.         DisposeRgn(oldClip);
  1069.         PenNormal();
  1070.  
  1071.         }
  1072.  
  1073. } // DrawSelection
  1074.  
  1075. // --------------------------------------------------------------------------------------------------------------
  1076. OSStatus SelectContents(WindowPtr pWindow, WindowDataPtr pData, EventRecord *pEvent, Rect *pSelection, Rect *pContent, short *pPhase)
  1077. {
  1078.  
  1079.     OSStatus            anErr = noErr;
  1080.     Point            clickPoint = pEvent->where;
  1081.     Point            currentPoint;
  1082.     Boolean         didJustScroll;
  1083.     ControlHandle    theControl;
  1084.     
  1085.     GlobalToLocal(&clickPoint);
  1086.     if (FindControl(clickPoint, pWindow, &theControl) == 0)
  1087.         {
  1088.     
  1089.         // move the click point into the proper range
  1090.         clickPoint.h += GetControlValue(pData->hScroll);
  1091.         clickPoint.v += GetControlValue(pData->vScroll);
  1092.         
  1093.         // if the shift key is held down then the selection starts from
  1094.         // a preexisting point such that we are doing an expand/contract
  1095.         // of the original selection
  1096.         if (pEvent->modifiers & shiftKey)
  1097.             {
  1098.             if (clickPoint.h < pSelection->right)
  1099.                 clickPoint.h = pSelection->right;
  1100.             else
  1101.                 clickPoint.h = pSelection->left;
  1102.  
  1103.             if (clickPoint.v < pSelection->bottom)
  1104.                 clickPoint.v = pSelection->bottom;
  1105.             else
  1106.                 clickPoint.v = pSelection->top;
  1107.             }
  1108.                         
  1109.         while (StillDown())
  1110.             {                    
  1111.             CGrafPtr thePort = GetQDGlobalsThePort();
  1112.  
  1113.             // get the current mouse 
  1114.             GetMouse(¤tPoint);
  1115.             
  1116.             didJustScroll = false;
  1117.             // scroll contents if needed
  1118.             {
  1119.             short    deltaH = 0;
  1120.             short    deltaV = 0;
  1121.             Rect    bounds;
  1122.  
  1123.             GetPortBounds(thePort, &bounds);
  1124.             if (currentPoint.h < 0)
  1125.                 deltaH = pData->hScrollAmount;
  1126.                         if (currentPoint.h > bounds.right)
  1127.                 deltaH = -pData->hScrollAmount;
  1128.             if (currentPoint.v < 0)
  1129.                 deltaV = pData->vScrollAmount;
  1130.                         if (currentPoint.v > bounds.bottom)
  1131.                 deltaV = -pData->vScrollAmount;
  1132.                 
  1133.             if ( (deltaH != 0) || (deltaV != 0) )
  1134.                 {                
  1135.                 if (deltaH)
  1136.                     SetControlAndClipAmount(pData->hScroll, &deltaH);
  1137.                 if (deltaV)
  1138.                     SetControlAndClipAmount(pData->vScroll, &deltaV);
  1139.  
  1140.                 DoScrollContent(pWindow, pData, deltaH, deltaV);
  1141.                 
  1142.                 didJustScroll = true;
  1143.                 }
  1144.             }
  1145.             
  1146.             // map mouse into proper range
  1147.             currentPoint.h += GetControlValue(pData->hScroll);
  1148.             currentPoint.v += GetControlValue(pData->vScroll);
  1149.     
  1150.             // clip to the document size
  1151.             if (currentPoint.h < 0)
  1152.                 currentPoint.h = 0;
  1153.             if (currentPoint.v < 0)
  1154.                 currentPoint.v = 0;
  1155.             if (currentPoint.h > pContent->right)
  1156.                 currentPoint.h = pContent->right;
  1157.             if (currentPoint.v > pContent->bottom)
  1158.                 currentPoint.v = pContent->bottom;
  1159.                 
  1160.             // draw the new selection if it is time or we are about to 
  1161.             // exit this loop
  1162.             if ((MOVESELECTION(TickCount())) || (!Button()) || (didJustScroll) )
  1163.                 {
  1164.                 // first, erase any old selection we might have had
  1165.                 DrawSelection(pData, pSelection, pPhase, false);
  1166.  
  1167.                 // make a rectangle out of the two points
  1168.                 pSelection->left     = Min(currentPoint.h, clickPoint.h);
  1169.                 pSelection->right     = Max(currentPoint.h, clickPoint.h);
  1170.                 pSelection->top     = Min(currentPoint.v, clickPoint.v);
  1171.                 pSelection->bottom     = Max(currentPoint.v, clickPoint.v);
  1172.     
  1173.                 // draw the new selection
  1174.                 DrawSelection(pData, pSelection, pPhase, true);
  1175.                 }
  1176.             }
  1177.         
  1178.         // we handled the selection
  1179.         anErr = eActionAlreadyHandled;
  1180.         }
  1181.         
  1182.     return(anErr);
  1183.     
  1184. } // SelectContents
  1185.  
  1186. // --------------------------------------------------------------------------------------------------------------
  1187. void DragAndDropArea(WindowPtr pWindow, WindowDataPtr pData, EventRecord* event, Rect *pFrameRect)
  1188. {
  1189.     RgnHandle        hilightRgn;
  1190.     DragReference    theDrag;
  1191.     OSStatus            anErr = noErr;
  1192.  
  1193.     if (!WaitMouseMoved (event->where))
  1194.     {
  1195.         return;
  1196.     }
  1197.         
  1198.     if (NewDrag(&theDrag) == noErr)
  1199.         {
  1200.         
  1201.         // add the flavor for the window title, errors can be ignored as this
  1202.         // is a cosmetic addition
  1203.         {
  1204.         enum
  1205.             {
  1206.             kFlavorTypeClippingName = 'clnm'
  1207.             };
  1208.         Str255    windowTitle;
  1209.         
  1210.         GetWTitle(pWindow, windowTitle);
  1211.         (void)     AddDragItemFlavor(theDrag, 1, kFlavorTypeClippingName, &windowTitle, windowTitle[0]+1, flavorNotSaved);
  1212.         }
  1213.         
  1214.         if (pData->pDragAddFlavors)
  1215.             anErr = (*(pData->pDragAddFlavors)) (pWindow, pData, theDrag);
  1216.         
  1217.         if (anErr == noErr)
  1218.             {
  1219.             Rect    globalRect = *pFrameRect;
  1220.             
  1221.             hilightRgn = NewRgn();    
  1222.             LocalToGlobal(&TopLeft(globalRect));
  1223.             LocalToGlobal(&BotRight(globalRect));
  1224.             RectRgn(hilightRgn, &globalRect);
  1225.             SetDragItemBounds(theDrag, 1, &globalRect);
  1226.     
  1227.             // turn the region from a fill into a frame
  1228.             {    
  1229.                 RgnHandle tempRgn = NewRgn();
  1230.     
  1231.                 CopyRgn(hilightRgn, tempRgn);
  1232.                 InsetRgn(tempRgn, 1, 1);
  1233.                 DiffRgn(hilightRgn, tempRgn, hilightRgn);
  1234.                 DisposeRgn(tempRgn);
  1235.             }
  1236.             
  1237.             TrackDrag(theDrag, event, hilightRgn);
  1238.             DisposeDrag(theDrag);
  1239.             DisposeRgn(hilightRgn);
  1240.             }
  1241.         }
  1242.  
  1243. } // DragAndDropArea
  1244.  
  1245. // --------------------------------------------------------------------------------------------------------------
  1246. // WINDOW UTILITY ROUTINES
  1247. // --------------------------------------------------------------------------------------------------------------
  1248. static void CalculateGrowIcon(WindowPtr pWindow,WindowDataPtr pData, Rect * location)
  1249. {
  1250. #pragma unused (pWindow)
  1251.  
  1252.     Rect bounds;
  1253.  
  1254.     if (pData->vScroll) {
  1255.             GetControlBounds(pData->vScroll, &bounds);
  1256.         location->top = bounds.bottom;
  1257.     } else {
  1258.         if (pData->hScroll) {
  1259.                         GetControlBounds(pData->hScroll, &bounds);
  1260.                         location->top = bounds.top;
  1261.         } else {
  1262.             GetWindowPortBounds(pData->theWindow, &bounds);
  1263.             location->top = bounds.bottom - 15;
  1264.         }
  1265.     }
  1266.         
  1267.     if (pData->hScroll) {
  1268.                 GetControlBounds(pData->hScroll, &bounds);
  1269.                 location->left = bounds.right;
  1270.     } else {
  1271.         if (pData->vScroll) {
  1272.                        GetControlBounds(pData->vScroll, &bounds);
  1273.             location->left = bounds.left;
  1274.         } else {
  1275.                         GetWindowPortBounds(pData->theWindow, &bounds);
  1276.                         location->left = bounds.right - 15;
  1277.             }
  1278.     }
  1279.  
  1280.     location->right = location->left + 16;
  1281.     location->bottom = location->top + 16;
  1282.     
  1283. } // CalculateGrowIcon
  1284.  
  1285. // --------------------------------------------------------------------------------------------------------------
  1286. //
  1287. // Set the modified bit for the window
  1288. //
  1289. void SetDocumentContentChanged( WindowDataPtr pData, Boolean changed )
  1290. {
  1291.     pData->changed = changed;
  1292.         
  1293.     if( gMachineInfo.haveProxyIcons )
  1294.         SetWindowModified( pData->theWindow, changed );
  1295.  
  1296. }
  1297.  
  1298.  
  1299. // --------------------------------------------------------------------------------------------------------------
  1300. OSStatus    AdjustScrollBars(WindowRef pWindow,
  1301.     Boolean moveControls,                 // might the controls have moved?
  1302.     Boolean didResize,                     // did we just resize the window?
  1303.     Boolean *needInvalidate)            // does the caller need to invalidate contents as a result?
  1304. {
  1305.     OSStatus            anErr = noErr;
  1306.     LongRect        docRect;
  1307.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  1308.     Rect            growIconRect;
  1309.     
  1310.     if (needInvalidate)
  1311.         *needInvalidate = false;
  1312.  
  1313.     if (pData)
  1314.         {
  1315.         short    oldHMax = 0;
  1316.         short    oldVMax = 0;
  1317.         short    oldHValue = 0;
  1318.         short    oldVValue = 0;
  1319.                 Rect bounds;
  1320.         
  1321.         // cache current values, we'll force an update if we needed to change em!
  1322.         if (pData->hScroll)
  1323.             {
  1324.             oldHMax = GetControlMaximum(pData->hScroll);
  1325.             oldHValue = GetControlValue(pData->hScroll);
  1326.             }
  1327.         if (pData->vScroll)
  1328.             {
  1329.             oldVMax = GetControlMaximum(pData->vScroll);
  1330.             oldVValue = GetControlValue(pData->vScroll);
  1331.             }
  1332.             
  1333.         // if we have a grow box but not all controls we have to invalidate the grow bar areas
  1334.         // by caclulating them
  1335.         if ( (didResize) && (pData->hasGrow) )
  1336.             {
  1337.                         GetWindowPortBounds(pWindow, &bounds);
  1338.  
  1339.             // if we regrow without any scroll bars, we need to update the content area
  1340.             if ( (needInvalidate) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  1341.                 *needInvalidate = true;
  1342.             
  1343.             // invalidate old grow bar areas
  1344.             if (pData->vScroll == nil)
  1345.                 {
  1346.                 growIconRect = bounds;
  1347.                 growIconRect.left = pData->contentRect.right;
  1348.                 InvalWindowRect(pWindow,&growIconRect);
  1349.                 }
  1350.             if (pData->hScroll == nil)
  1351.                 {
  1352.                                 growIconRect = bounds;
  1353.                 growIconRect.top = pData->contentRect.bottom;
  1354.                 InvalWindowRect(pWindow,&growIconRect);
  1355.                 }
  1356.             
  1357.             // invalidate new grow bar areas
  1358.             if (pData->vScroll == nil)
  1359.                 {
  1360.                                 growIconRect = bounds;
  1361.                 growIconRect.left = growIconRect.right - kScrollBarSize;
  1362.                 InvalWindowRect(pWindow,&growIconRect);
  1363.                 }
  1364.             if (pData->hScroll == nil)
  1365.                 {
  1366.                                 growIconRect = bounds;
  1367.                 growIconRect.top = growIconRect.bottom - kScrollBarSize;
  1368.                 InvalWindowRect(pWindow,&growIconRect);
  1369.                 }
  1370.             }
  1371.             
  1372.         // if the controls need moving, recalculate the visible area
  1373.         if (moveControls)
  1374.             {
  1375.                         growIconRect = bounds;
  1376.             if ((pData->hScroll) || (pData->hasGrow) )
  1377. #if 0
  1378. //                pData->contentRect.bottom -= kScrollBarSize;
  1379. //                This made the viewRect smaller and smaller when backspacing.
  1380. //                See TextKeyEvent (TextFile.c)  Adjust from real bounds instead of previous.
  1381. #endif
  1382.                 pData->contentRect.bottom = bounds.bottom - kScrollBarSize;
  1383.             if ((pData->vScroll) || (pData->hasGrow) )
  1384. #if 0
  1385. //                pData->contentRect.right -= kScrollBarSize;
  1386. //                (same fix as 'contentRect.bottom' above.)
  1387. #endif
  1388.                 pData->contentRect.right = bounds.right - kScrollBarSize;
  1389.             }
  1390.             
  1391.         // before doing anything, make the controls invisible
  1392.         if (pData->hScroll)
  1393.                     SetControlVisibility(pData->hScroll, false, false);
  1394.         if (pData->vScroll)
  1395.                     SetControlVisibility(pData->vScroll, false, false);
  1396.  
  1397.         // based on document and visiable area, adjust possible control values
  1398.         if ( (pData->pGetDocumentRect) && ((pData->hScroll) || (pData->vScroll)) )
  1399.             {
  1400.             // let the object calc the size and content if it wishes to
  1401.             anErr = (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, false);
  1402.             if (anErr == noErr)
  1403.                 {
  1404.                 short    amountOver;
  1405.                 short    newMax;
  1406.                 
  1407.                 amountOver = (docRect.right - docRect.left) - (pData->contentRect.right - pData->contentRect.left);
  1408.                 if     (
  1409.                     (pData->hScroll) &&
  1410.                     (amountOver > 0)
  1411.                     )
  1412.                     newMax = amountOver;
  1413.                 else
  1414.                     newMax = 0;
  1415.     
  1416.                 if (pData->hScroll)
  1417.                     {
  1418.                     if (GetControlValue(pData->hScroll) > newMax)
  1419.                         {
  1420.                         if (needInvalidate)
  1421.                             *needInvalidate = true;
  1422.                         }
  1423.                     SetControlMaximum(pData->hScroll, newMax);
  1424.                     }
  1425.                 
  1426.                 amountOver = (docRect.bottom - docRect.top) - (pData->contentRect.bottom - pData->contentRect.top);
  1427.                 if     (
  1428.                     (pData->vScroll) &&
  1429.                     (amountOver > 0)
  1430.                     )
  1431.                     newMax = amountOver;
  1432.                 else
  1433.                     newMax = 0;
  1434.                     
  1435.                 if (pData->vScroll)
  1436.                     {
  1437.                     if (GetControlValue(pData->vScroll) > newMax)
  1438.                         {
  1439.                         if (needInvalidate)
  1440.                             *needInvalidate = true;
  1441.                         }
  1442.                     SetControlMaximum(pData->vScroll, newMax);
  1443.                     }
  1444.                 }
  1445.             }
  1446.             
  1447.         // then, if the controls need moving, we move them and inval the old
  1448.         // and new locations
  1449.         if (moveControls)
  1450.             {
  1451.             // if we have grow box we invalidate the old grow location
  1452.             if ( pData->hasGrow) 
  1453.                 {
  1454.                 CalculateGrowIcon(pWindow, pData, &growIconRect);
  1455.                 InvalWindowRect(pWindow,&growIconRect);
  1456.                 }
  1457.                 
  1458.             if (pData->hScroll)
  1459.                 {
  1460.                 short    widthAdjust;
  1461.                 Rect bounds;
  1462.                 
  1463.                 if ((pData->vScroll) || (pData->hasGrow))
  1464.                     widthAdjust = -kGrowScrollAdjust;
  1465.                 else
  1466.                     widthAdjust = -1;
  1467.                     
  1468.                 GetControlBounds(pData->hScroll, &bounds);
  1469.                 InvalWindowRect( pWindow, &bounds);
  1470.  
  1471.                 GetWindowPortBounds(pWindow, &bounds);
  1472.                                 MoveControl(pData->hScroll, pData->hScrollOffset - 1, bounds.bottom - kScrollBarSize);
  1473.                                 SizeControl(pData->hScroll, (bounds.right - bounds.left) + widthAdjust - pData->hScrollOffset, 16);
  1474.  
  1475.                                 GetControlBounds(pData->hScroll, &bounds);
  1476.                                 InvalWindowRect( pWindow, &bounds);
  1477.                 }
  1478.  
  1479.             if (pData->vScroll)
  1480.                 {
  1481.                 short    heightAdjust;
  1482.                 
  1483.                 if ((pData->hScroll) || (pData->hasGrow))
  1484.                     heightAdjust = -kGrowScrollAdjust;
  1485.                 else
  1486.                     heightAdjust = -1;
  1487.                     
  1488.                 GetControlBounds(pData->vScroll, &bounds);
  1489.                                 InvalWindowRect( pWindow, &bounds);
  1490.  
  1491.                                 GetWindowPortBounds(pWindow, &bounds);
  1492.                                 MoveControl(pData->vScroll, bounds.right - kScrollBarSize, pData->vScrollOffset-1);
  1493.                                 SizeControl(pData->vScroll, 16, (bounds.bottom - bounds.top) + heightAdjust - pData->vScrollOffset);
  1494.  
  1495.                                 GetControlBounds(pData->vScroll, &bounds);
  1496.                                 InvalWindowRect( pWindow, &bounds);
  1497.                 }
  1498.                 
  1499.             // if we have scroll bars, update the grow icon
  1500.             if ( pData->hasGrow )
  1501.                 {
  1502.                 CalculateGrowIcon(pWindow,pData, &growIconRect);
  1503.                 InvalWindowRect(pWindow,&growIconRect);
  1504.                 }
  1505.             
  1506.             }
  1507.  
  1508.         // let the document adjust anything it needs to
  1509.         if (pData->pAdjustSize)
  1510.             anErr = (*(pData->pAdjustSize)) (pWindow, pData, &didResize);
  1511.             
  1512.         if ((didResize) && (needInvalidate))
  1513.             *needInvalidate = true;
  1514.  
  1515.  
  1516.                 if ( IsWindowHilited(pWindow) )
  1517.             {
  1518.             // after doing something, make the controls visible
  1519.             if (pData->hScroll)
  1520.                 {
  1521.                 if ((oldHMax != GetControlMaximum(pData->hScroll)) || (oldHValue != GetControlValue(pData->hScroll)) )
  1522.                                     ShowControl(pData->hScroll);
  1523.                 else
  1524.                                     SetControlVisibility(pData->hScroll, true, false);    
  1525.                 }
  1526.             if (pData->vScroll)
  1527.                 {
  1528.                 if ((oldVMax != GetControlMaximum(pData->vScroll)) || (oldVValue != GetControlValue(pData->vScroll)) )
  1529.                     ShowControl(pData->vScroll);
  1530.                 else
  1531.                                     SetControlVisibility(pData->vScroll, true, false);    
  1532.                 }
  1533.             }
  1534.  
  1535.         }
  1536.         
  1537.     return anErr;
  1538.     
  1539. } // AdjustScrollBars
  1540.  
  1541. // --------------------------------------------------------------------------------------------------------------
  1542. // MENU UTILITY ROUTINES
  1543. // --------------------------------------------------------------------------------------------------------------
  1544. Boolean CommandToIDs(short commandID, short * menuID, short *itemID)
  1545. {
  1546.  
  1547.     short    ** commandHandle;
  1548.     short    whichMenu;
  1549.     short    oldResFile = CurResFile();
  1550.     Boolean    returnValue = false;
  1551.     
  1552.     UseResFile(gApplicationResFile);
  1553.     for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++)
  1554.         {
  1555.         commandHandle = (short**) Get1Resource('MCMD', whichMenu);
  1556.         if (commandHandle)
  1557.             {
  1558.             short    * pCommands = *commandHandle;
  1559.             short    commandIndex;
  1560.             short    numCommands = pCommands[0];
  1561.             
  1562.             for (commandIndex = 1; commandIndex <= numCommands; ++commandIndex)
  1563.                 if (pCommands[commandIndex] == commandID)
  1564.                     {
  1565.                     *menuID = whichMenu;
  1566.                     *itemID = commandIndex;
  1567.                     
  1568.                     returnValue = (commandIndex == numCommands);
  1569.                     }
  1570.             }    
  1571.         }
  1572.         
  1573.     UseResFile(oldResFile);
  1574.     
  1575.     return returnValue;
  1576.     
  1577. } // CommandToIDs
  1578.  
  1579. // --------------------------------------------------------------------------------------------------------------
  1580. Boolean IsCommandEnabled(short commandID)
  1581. /*
  1582.     returns true if a given command is currently enabled
  1583. */
  1584. {
  1585.     short        whichMenu, whichItem;
  1586.     MenuHandle    menu;
  1587.     
  1588.     CommandToIDs(commandID, &whichMenu, &whichItem);
  1589.     menu = GetMenuHandle(whichMenu);
  1590.     
  1591.         if (IsMenuItemEnabled(menu, whichItem))
  1592.         return(true);
  1593.     
  1594.     return(false);
  1595.     
  1596. } // IsCommandEnabled
  1597.  
  1598. // --------------------------------------------------------------------------------------------------------------
  1599. void EnableCommand(short commandID)
  1600. /*
  1601.     Given a command ID, enables the first menu item with that command ID.
  1602.     
  1603.     If the command table for a given menu is less than the number of items in the menu,
  1604.     and the command being enabled is the last item in the command table, then all
  1605.     items from there on down are also enabled.  This is useful for menus that get
  1606.     appended to, such as the desk accessory list, font list, or speaking voices list.
  1607. */
  1608. {
  1609.     short    whichMenu;
  1610.     short    whichItem;
  1611.     
  1612.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1613.         {
  1614.         short        i;
  1615.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1616.         
  1617.         if (menu)
  1618.             {
  1619.             short        numItems = CountMenuItems(menu);
  1620.             
  1621.             for (i = whichItem; i <= numItems; ++i)
  1622.                 EnableMenuItem(menu, i);
  1623.             }
  1624.         }
  1625.     else
  1626.         {
  1627.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1628.  
  1629.         if (menu)
  1630.             EnableMenuItem(menu, whichItem);
  1631.         }
  1632.         
  1633. } // EnableCommand
  1634.  
  1635. // --------------------------------------------------------------------------------------------------------------
  1636. void ChangeCommandName(short commandID, short resourceID, short resourceIndex)
  1637. {
  1638.     short        whichMenu;
  1639.     short        whichItem;
  1640.     MenuHandle    menu;
  1641.     
  1642.     // figure out how this command maps into the menu bar
  1643.     CommandToIDs(commandID, &whichMenu, &whichItem);
  1644.     menu = GetMenuHandle(whichMenu);
  1645.     
  1646.     // then make this item into the requested new string
  1647.     {
  1648.     Str255        theString;
  1649.     
  1650.     GetIndString(theString, resourceID, resourceIndex);
  1651.     SetMenuItemText(menu, whichItem, theString);
  1652.     }
  1653.     
  1654. } // ChangeCommandName
  1655.  
  1656. // --------------------------------------------------------------------------------------------------------------
  1657. void EnableCommandCheck(short commandID, Boolean check)
  1658. {
  1659.  
  1660.     short    whichMenu;
  1661.     short    whichItem;
  1662.     
  1663.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1664.         {
  1665.         short        i;
  1666.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1667.         short        numItems = CountMenuItems(menu);
  1668.         
  1669.         for (i = whichItem; i <= numItems; ++i)
  1670.             {
  1671.             EnableMenuItem(menu, i);
  1672.             MacCheckMenuItem(menu, i, check);
  1673.             }
  1674.         }
  1675.     else
  1676.         {
  1677.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1678.  
  1679.         EnableMenuItem(menu, whichItem);
  1680.         MacCheckMenuItem(menu, whichItem, check);
  1681.         }
  1682.         
  1683. } // EnableCommandCheck
  1684.  
  1685.  
  1686. // --------------------------------------------------------------------------------------------------------------
  1687. void EnableCommandCheckStyle(short commandID, Boolean check, short style)
  1688. {
  1689.  
  1690.     short    whichMenu;
  1691.     short    whichItem;
  1692.     
  1693.     if (CommandToIDs(commandID, &whichMenu, &whichItem))
  1694.         {
  1695.         short        i;
  1696.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1697.         short        numItems = CountMenuItems(menu);
  1698.         
  1699.         for (i = whichItem; i <= numItems; ++i)
  1700.             {
  1701.             EnableMenuItem(menu, i);
  1702.             MacCheckMenuItem(menu, i, check);
  1703.             SetItemStyle(menu, i, style);
  1704.             }
  1705.         }
  1706.     else
  1707.         {
  1708.         MenuHandle    menu = GetMenuHandle(whichMenu);
  1709.  
  1710.         EnableMenuItem(menu, whichItem);
  1711.         MacCheckMenuItem(menu, whichItem, check);
  1712.         SetItemStyle(menu, whichItem, style);
  1713.         }
  1714.         
  1715. } // EnableCommandCheckStyle
  1716.  
  1717. // --------------------------------------------------------------------------------------------------------------
  1718. static     void    DisableEntireMenu(MenuHandle menu);        
  1719. static     void    DisableEntireMenu(MenuHandle menu)
  1720. {
  1721.     SInt16 i, count;
  1722.  
  1723.     count = CountMenuItems(menu);
  1724.  
  1725.     for (i = 0; i <= count; i++)
  1726.     {
  1727.             DisableMenuItem(menu, i);
  1728.     }
  1729. }
  1730.  
  1731. static Boolean IsAnyMenuItemEnabled(MenuHandle menu);
  1732. static Boolean IsAnyMenuItemEnabled(MenuHandle menu)
  1733. {
  1734.     SInt16 i, count;
  1735.  
  1736.     count = CountMenuItems(menu);
  1737.  
  1738.     for (i = 1; i <= count; i++)
  1739.     {
  1740.         if (IsMenuItemEnabled(menu, i))
  1741.         return(true);
  1742.     }
  1743.  
  1744.     return(false);
  1745. }
  1746.  
  1747. Boolean AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn)
  1748. {
  1749.     Boolean                 wasEnabled[mNumberMenus];    // Old state of menus
  1750.     MenuHandle                menus[mNumberMenus];
  1751.     short                    whichMenu;            // for stepping through menus
  1752.     MenuHandle                menu;                // for reading in menu IDs
  1753.     WindowDataPtr                 pData = GetWindowInfo(pWindow);
  1754.     
  1755.     // Step through all of the menus 
  1756.     for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++)
  1757.         {
  1758.         // Save the old state of the menu title 
  1759.         menus[whichMenu - mApple] = menu = GetMenuHandle(whichMenu);
  1760.         if (menu)                                // because contents menu may not be around
  1761.             {
  1762.             if (forceTitlesOn)                
  1763.                 wasEnabled[mLastMenu - whichMenu] = false;
  1764.             else
  1765.                             wasEnabled[mLastMenu - whichMenu] = IsMenuItemEnabled(menu, 0);
  1766.             
  1767.             // Disable the entire menu 
  1768.             DisableEntireMenu(menu);        
  1769.             }
  1770.         }
  1771.     
  1772.     // select all, unless someone else changes it
  1773.     ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  1774.  
  1775.     // if we have NO windows, or the current window is one we understand
  1776.     if ((pWindow == nil) || (pData))
  1777.         {
  1778.         // enable the default commands
  1779.         EnableCommand(cAbout);
  1780.         EnableCommand(cDeskAccessory);
  1781.         
  1782.         EnableCommand(cNew);
  1783.         EnableCommand(cOpen);
  1784.         EnableCommand(cQuit);
  1785.     
  1786.         EnableCommand(cShowClipboard);
  1787.         }
  1788.     else
  1789.         {
  1790.         // it's printing or a dialog, so enable cut/copy/paste
  1791.         if (editDialogs)
  1792.             {
  1793.             EnableCommand(cCut);
  1794.             EnableCommand(cCopy);
  1795.             EnableCommand(cPaste);
  1796.             EnableCommand(cClear);
  1797.             }
  1798.         
  1799.         // and desk accs too!        
  1800.         EnableCommand(cDeskAccessory);
  1801.  
  1802.         }
  1803.         
  1804.     if ( (pWindow) && (pData) )
  1805.         {
  1806.         // all windows can be closed
  1807.         if (FrontWindow())
  1808.             EnableCommand(cClose);
  1809.  
  1810.         // changed documents can be saved, but only if the file is open for write
  1811.         if (     (pData->changed) && 
  1812.                 ((pData->isWritable) || (pData->dataRefNum == -1)) )
  1813.             EnableCommand(cSave);
  1814.         
  1815.         // objects with a print method can be printed and page setup-ed
  1816.         if (pData->pPrintPage)
  1817.             {
  1818.             EnableCommand(cPrint);
  1819.             EnableCommand(cPageSetup);
  1820.             EnableCommand(cPrintOneCopy);
  1821.             }
  1822.             
  1823.         // let object enable anything else that needs to be enabled
  1824.         if (pData->pAdjustMenus)
  1825.             (*(pData->pAdjustMenus)) (pWindow, pData);
  1826.         }
  1827.         
  1828.     // Now determine if any of the menus have changed state
  1829.     {
  1830.     Boolean gotToRedraw = false;
  1831.     
  1832.     for (whichMenu = mApple; whichMenu <= mLastMenu; ++whichMenu)
  1833.         {
  1834.         menu = menus[whichMenu - mApple];
  1835.     
  1836.         if (menu)        // because contents menu may not be around
  1837.             {
  1838.             // If any of the menu is enabled
  1839.                         if (IsAnyMenuItemEnabled(menu))
  1840.                 {
  1841.                 // Make sure to turn on the menu title
  1842.                                 EnableMenuItem(menu, 0);
  1843.                 }
  1844.                 
  1845.             /*     If this new state is different than the saved state, then the menu bar
  1846.                 will need to be redrawn */
  1847.             if (wasEnabled[mLastMenu - whichMenu] != IsMenuItemEnabled(menu, 0))
  1848.                 {
  1849.                 gotToRedraw = true;
  1850.                 }
  1851.             }
  1852.         }
  1853.         
  1854.     // And if any titles have changed state, redraw them 
  1855.     if (gotToRedraw)
  1856.         InvalMenuBar();
  1857.         
  1858.     return gotToRedraw;
  1859.     }
  1860.         
  1861. } // AdjustMenus
  1862.  
  1863. // --------------------------------------------------------------------------------------------------------------
  1864. // FILE UTILITY ROUTINES
  1865. // --------------------------------------------------------------------------------------------------------------
  1866. static Boolean BringToFrontIfOpen(FSSpecPtr pSpec)
  1867. {
  1868.     WindowPtr        pWindow;
  1869.     
  1870.     pWindow = FrontWindow();
  1871.     while (pWindow)
  1872.         {
  1873.         WindowDataPtr pData = GetWindowInfo(pWindow);
  1874.         
  1875.         if (
  1876.             (pData) &&
  1877.             (pData->fileSpec.vRefNum == pSpec->vRefNum) &&
  1878.             (pData->fileSpec.parID == pSpec->parID) &&
  1879.             EqualString(pData->fileSpec.name, pSpec->name, false, false)
  1880.             )
  1881.             {
  1882.             SelectWindow(pWindow);
  1883.             return true;
  1884.             }
  1885.             
  1886.         pWindow = GetNextWindow(pWindow);
  1887.         }
  1888.         
  1889.     return false;
  1890.     
  1891. } // BringToFrontIfOpen
  1892.  
  1893. // --------------------------------------------------------------------------------------------------------------
  1894. static Boolean BringToFrontIfExists(ResType windowKind)
  1895. {
  1896.     WindowPtr        pWindow;
  1897.     
  1898.     pWindow = FrontWindow();
  1899.     while (pWindow)
  1900.         {
  1901.         WindowDataPtr pData = GetWindowInfo(pWindow);
  1902.         
  1903.         if ((pData) && (pData->windowKind == windowKind))
  1904.             {
  1905.             SelectWindow(pWindow);
  1906.             return true;
  1907.             }
  1908.             
  1909.         pWindow = GetNextWindow(pWindow);
  1910.         }
  1911.         
  1912.     return false;
  1913.     
  1914. } // BringToFrontIfExists
  1915.  
  1916. // --------------------------------------------------------------------------------------------------------------
  1917. // MAIN SIMPLETEXT ROUTINES
  1918. // --------------------------------------------------------------------------------------------------------------
  1919. static OSStatus MakeNewWindow(ResType windowKind, FSSpecPtr fileSpec, OSType fileType, Boolean *pWasAlreadyOpen)
  1920. {
  1921.     OSStatus                anErr = fnfErr;
  1922.     PreflightRecord        thePreflight;
  1923.     PreflightWindowProc    pPreflight = nil;
  1924.     WindowPtr            pWindow;
  1925.     WindowDataPtr        pData;
  1926.     ControlHandle        rootControl;
  1927.     
  1928.     // require a certain amount of RAM free before we allow the new window to be created
  1929.     if (FreeMem() < kRAMNeededForNew)
  1930.         anErr = memFullErr;
  1931.         
  1932.     // make sure we update the cursor
  1933.     SetEmptyRgn(gCursorRgn);
  1934.     
  1935.     // <50> if we already have a document open from this file, bring the window to the
  1936.     // front and return with no error
  1937.     if ( (fileSpec) && (fileType != 'sEXT') && (BringToFrontIfOpen(fileSpec)) )
  1938.         {
  1939.         if (pWasAlreadyOpen)
  1940.             *pWasAlreadyOpen = true;
  1941.         anErr = noErr;
  1942.         return(anErr);
  1943.         }
  1944.     if (pWasAlreadyOpen)
  1945.         *pWasAlreadyOpen = false;
  1946.     if (anErr != fnfErr)
  1947.         {
  1948.         nrequire(anErr, SanityCheckFailed);
  1949.         }
  1950.         
  1951.     // initialize our behavior
  1952.     thePreflight.continueWithOpen     = true;
  1953.     thePreflight.resourceID         = kDefaultWindowID;
  1954.     thePreflight.wantHScroll         = false;
  1955.     thePreflight.wantVScroll         = false;
  1956.     thePreflight.storageSize         = sizeof(WindowDataRecord);
  1957.     thePreflight.makeProcPtr         = nil;
  1958.     thePreflight.openKind            = fsRdPerm;
  1959.     thePreflight.needResFork        = false;
  1960.     thePreflight.doZoom                = false;
  1961.     thePreflight.fileType            = fileType;
  1962.     
  1963.     switch (windowKind)
  1964.         {
  1965.         case kAboutWindow:
  1966.             pPreflight = AboutPreflightWindow;
  1967.             break;
  1968.  
  1969.         case kPICTWindow:
  1970.             pPreflight = PICTPreflightWindow;
  1971.             break;
  1972.  
  1973. #if ALLOW_QUICKTIME
  1974.         case kMovieWindow:
  1975.             pPreflight = MoviePreflightWindow;
  1976.             break;
  1977. #endif
  1978.  
  1979.         case kClipboardWindow:
  1980.             pPreflight = ClipboardPreflightWindow;
  1981.             break;
  1982.  
  1983.         case kTextWindow:
  1984.             pPreflight = TextPreflightWindow;
  1985.             break;
  1986.  
  1987. #if ALLOW_QUICKTIME
  1988.         case kThreeDWindow:
  1989.             pPreflight = ThreeDPreflightWindow;
  1990.             break;
  1991. #endif
  1992.         }
  1993.     
  1994.     // preflight the window    
  1995.     if (pPreflight)
  1996.         anErr = (*pPreflight) (&thePreflight);
  1997.     nrequire(anErr, PreflightFailed);
  1998.     
  1999.     if (thePreflight.continueWithOpen)
  2000.         {
  2001.         // allocate a place for the window
  2002.         pData = (WindowDataPtr)NewPtrClear(thePreflight.storageSize);
  2003.         anErr = MemError();
  2004.         nrequire(anErr, FailedToAllocateWindow);
  2005.         
  2006.         // then actually create the window
  2007.         pWindow = GetNewCWindow(thePreflight.resourceID, NULL, (WindowPtr)-1);
  2008.         if (!pWindow) anErr = memFullErr;
  2009.         nrequire(anErr, NewWindowFailed);
  2010.  
  2011.         pData->theWindow = pWindow;
  2012.         SetWRefCon(pWindow, (long) pData);
  2013.                 
  2014.         if (gMachineInfo.haveAppearanceMgr)
  2015.             CreateRootControl(pWindow, &rootControl);
  2016.                 
  2017.         // zoom the rectangle to big size on this monitor 
  2018.         // based upon which scroll bars they want
  2019.         {
  2020.         Rect    rect;
  2021.         Rect    bigRect;
  2022.  
  2023.         GetWindowPortBounds(pWindow, &rect);
  2024.         bigRect = (**GetMainDevice()).gdRect;
  2025.  
  2026.         bigRect.top += GetMBarHeight() * 2;
  2027.         bigRect.left += 4;
  2028.         bigRect.bottom -= 4;
  2029.         bigRect.right -= 65;    // ••• this is probably attempting to leave space for icons on the desktop.
  2030.  
  2031.         SetPortWindowPort (pWindow);
  2032.         LocalToGlobal(&TopLeft(rect));
  2033.         LocalToGlobal(&BotRight(rect));
  2034.         
  2035.         // can't have an invalid rectangle - this doesn't seem likely to happen
  2036. //        if (rect.right - rect.left < 32)
  2037. //            rect.right = rect.left + 32;
  2038.  
  2039. ///        MoveWindow(pWindow, rect.left, rect.top, false);
  2040.         SizeWindow(pWindow, rect.right - rect.left, rect.bottom - rect.top, false);
  2041.         }
  2042.         
  2043.         // fill in the default contents of the window
  2044.         pData->windowKind         = windowKind;
  2045.         pData->originalFileType        = fileType;
  2046.         pData->pMakeWindow         = (MakeWindowProc)thePreflight.makeProcPtr;
  2047.         pData->resRefNum        = -1;
  2048.         pData->dataRefNum        = -1;
  2049.         pData->isClosing        = false;
  2050.  
  2051.         GetWindowPortBounds(pWindow, &pData->contentRect);
  2052.         
  2053.         // make the scroll bars
  2054.         {
  2055.         Rect    controlRect;
  2056.         
  2057.         if (thePreflight.wantHScroll)
  2058.             {
  2059.             pData->contentRect.bottom -= kScrollBarSize;
  2060.             GetWindowPortBounds(pWindow, &controlRect);
  2061.             controlRect.top = controlRect.bottom - (kScrollBarSize + 1);
  2062.             if (thePreflight.wantVScroll)
  2063.                 controlRect.right -= kGrowScrollAdjust;
  2064.             OffsetRect(&controlRect, -1, 1);
  2065.                         // if compiling native, use CreateScrollBarControl, else use NewControl till CarbonLib 1.1
  2066. #if ( COMPILING_CARBONLIB )     //      CarbonLib 1.1 will support new control APIs
  2067.             pData->hScroll = NewControl (pWindow,&controlRect,"\p",true,0,0,0,kControlScrollBarLiveProc,0);
  2068. #else
  2069.             CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gHActionProc, &pData->hScroll );
  2070. #endif
  2071.             }
  2072.         if (thePreflight.wantVScroll)
  2073.             {
  2074.             pData->contentRect.right -= kScrollBarSize;
  2075.                     GetWindowPortBounds(pWindow, &controlRect);
  2076.                         controlRect.left = controlRect.right - (kScrollBarSize + 1);
  2077.             if (thePreflight.wantVScroll)
  2078.                 controlRect.bottom -= kGrowScrollAdjust;
  2079.             OffsetRect(&controlRect, 1, -1);
  2080.                         // if compiling native, use CreateScrollBarControl, else use NewControl till CarbonLib 1.1
  2081. #if ( COMPILING_CARBONLIB )     //      CarbonLib 1.1 will support new control APIs
  2082.             pData->vScroll = NewControl (pWindow,&controlRect,"\p",true,0,0,0,kControlScrollBarLiveProc,0);
  2083. #else
  2084.             CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gVActionProc, &pData->vScroll );
  2085. #endif
  2086.  
  2087. #if MOUSE_WHEEL_SUPPORT
  2088.             {
  2089.                 EventTypeSpec        mouseWheelEvent = { kEventClassMouse, kEventMouseWheelMoved };
  2090.                 InstallEventHandler( GetWindowEventTarget( pWindow ), GetMouseWheelHandler(), 1, &mouseWheelEvent, pData, NULL );
  2091.             }
  2092. #endif
  2093.  
  2094.             }
  2095.         }
  2096.  
  2097.         // got a name?  Open the file        
  2098.         if (fileSpec)
  2099.             {
  2100.             anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum);
  2101.             if     ( 
  2102.                     ((anErr == afpAccessDenied) || (anErr == opWrErr) || (anErr == permErr) ) && 
  2103.                     (thePreflight.openKind != fsRdPerm)
  2104.                 )
  2105.                 {
  2106.                 thePreflight.openKind = fsRdPerm;
  2107.                 pData->isWritable = false;
  2108.                 anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum);
  2109.                 }
  2110.             else
  2111.                 pData->isWritable = true;
  2112.             nrequire(anErr, FailedToOpenFile);
  2113.  
  2114.             // okay not to find a resource fork, because some don't have them                
  2115.             pData->resRefNum = FSpOpenResFile(fileSpec, thePreflight.openKind);
  2116.             
  2117.             // save the file spec in case someone is interested
  2118.             pData->fileSpec = *fileSpec;
  2119.             
  2120.             // alias for background file synchronization
  2121.             anErr = NewAlias( NULL, fileSpec, &pData->fileAlias );
  2122.             nrequire(anErr, GoshNoAlias );
  2123.             
  2124.             //
  2125.             // Most windows are not modifiable in SimpleText - only text files can be modified by SimpleText    
  2126.             //
  2127.             if( gMachineInfo.haveProxyIcons )
  2128.             {
  2129.                 SetWindowModified( pWindow, false );
  2130.                 SetWindowProxyFSSpec( pWindow, fileSpec );
  2131.             }
  2132.  
  2133.             }
  2134.             
  2135.         if (pData->pMakeWindow)
  2136.             {
  2137.             Rect oldContent = pData->contentRect;
  2138. #ifdef __MWERKS__
  2139. #if __option(profile)
  2140.             ProfilerSetStatus(true);
  2141. #endif
  2142. #endif
  2143.             anErr = (*(pData->pMakeWindow)) (pWindow, pData);
  2144. #ifdef __MWERKS__
  2145. #if __option(profile)
  2146.             ProfilerDump("\pmakewindow.prof");
  2147.             ProfilerSetStatus(false);
  2148.             ProfilerClear();
  2149. #endif
  2150. #endif
  2151.             if (!EqualRect(&oldContent, &pData->contentRect))
  2152.                 {
  2153.                 SizeWindow(pWindow, 
  2154.                         pData->contentRect.right  + (pData->vScroll != 0) * kScrollBarSize,
  2155.                         pData->contentRect.bottom + (pData->hScroll != 0) * kScrollBarSize,
  2156.                         false);
  2157.                 }
  2158.             }
  2159.         nrequire(anErr, FailedMakeWindow);
  2160.  
  2161.         // got a name?  Use it as the window title
  2162.         if ( (fileSpec) && (!pData->openAsNew) )
  2163.             SetWTitle(pWindow, fileSpec->name);
  2164.         else
  2165.             {
  2166.             if ((gMachineInfo.documentCount == 1) && (pData->windowKind == kTextWindow))
  2167.                 {
  2168.                 Str255 tempString;
  2169.         
  2170.                 GetIndString(tempString, kMiscStrings, iFirstNewDocumentTitle);    // get the "untitled" string (no number)
  2171.                 SetWTitle(pWindow, tempString);
  2172.                 }
  2173.             else
  2174.                 {
  2175.                 Str255    tempString;
  2176.                 Str32    numString;
  2177.     
  2178.                 GetWTitle(pWindow, tempString);
  2179.                 NumToString(gMachineInfo.documentCount, numString);
  2180.                 (void) ZeroStringSub(tempString, numString);
  2181.                 SetWTitle(pWindow, tempString);
  2182.                 }
  2183.  
  2184.             if (pData->bumpUntitledCount)
  2185.                 gMachineInfo.documentCount++;    // bump count if appropriate for this kind of document
  2186.             }
  2187.  
  2188.         // Make sure the scroll bars are reasonable in size, and move if they must
  2189.         AdjustScrollBars(pWindow, true, true, nil);
  2190.         
  2191.         // Show the scrollbars
  2192.         if( pData->hScroll != NULL )
  2193.             ShowControl( pData->hScroll );
  2194.             
  2195.         if( pData->vScroll != NULL )
  2196.             ShowControl( pData->vScroll );
  2197.         
  2198.         // finally, if all goes well, we can see the window itself!
  2199.         ShowWindow(pWindow);
  2200.         }
  2201.  
  2202.     return noErr;
  2203.  
  2204. // EXCEPTION HANDLING
  2205.  
  2206. FailedMakeWindow:
  2207.     DisposeHandle( (Handle)pData->fileAlias );
  2208.     
  2209. GoshNoAlias:
  2210.     if (pData->resRefNum != -1)
  2211.         CloseResFile(pData->resRefNum);
  2212.     if (pData->dataRefNum != -1)
  2213.         FSClose(pData->dataRefNum);
  2214.         
  2215. FailedToOpenFile:
  2216.     DisposeWindow(pWindow);
  2217.     
  2218. NewWindowFailed:
  2219.     DisposePtr((Ptr)pData);
  2220.     
  2221. FailedToAllocateWindow:
  2222. PreflightFailed:
  2223. SanityCheckFailed:
  2224.     return anErr;
  2225.     
  2226. } // MakeNewWindow
  2227.  
  2228. #if MOUSE_WHEEL_SUPPORT
  2229.  
  2230. static EventHandlerUPP
  2231. GetMouseWheelHandler()
  2232. {
  2233.     static EventHandlerUPP    sHandler = NULL;
  2234.  
  2235.     if ( sHandler == NULL )
  2236.         sHandler = NewEventHandlerUPP( MouseWheelHandler );
  2237.  
  2238.     return sHandler;
  2239. }
  2240.  
  2241. static OSStatus
  2242. MouseWheelHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* userData )
  2243. {
  2244.     OSStatus                result = eventNotHandledErr;
  2245.     EventMouseWheelAxis        axis;
  2246.     SInt32                    delta;
  2247.     WindowDataPtr             pData = (WindowDataPtr)userData;
  2248.  
  2249.     GetEventParameter( inEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis,
  2250.         NULL, sizeof( EventMouseWheelAxis ), NULL, &axis );    
  2251.     GetEventParameter( inEvent, kEventParamMouseWheelDelta, typeLongInteger,
  2252.         NULL, sizeof( SInt32 ), NULL, &delta );    
  2253.  
  2254.     if ( axis == kEventMouseWheelAxisY )
  2255.     {
  2256.         VActionProc( pData->vScroll, delta > 0 ? kControlUpButtonPart : kControlDownButtonPart );
  2257.  
  2258.         result = noErr;
  2259.     }
  2260.     
  2261.     return result;
  2262. }
  2263. #endif
  2264.  
  2265. // --------------------------------------------------------------------------------------------------------------
  2266. static Boolean CanCloseWindow( WindowPtr pWindow )
  2267. {
  2268.     WindowDataPtr    pData = GetWindowInfo( pWindow );
  2269.     return ( pData == NULL || !pData->changed );
  2270. }
  2271.  
  2272.  
  2273. // --------------------------------------------------------------------------------------------------------------
  2274. static OSStatus DoCloseWindow( WindowPtr pWindow, Boolean discard, long keyTime )
  2275. {
  2276.     OSStatus        anErr = noErr;
  2277.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2278.     
  2279.     if ( !discard && (pData) && (pData->changed) )
  2280.     {
  2281.         if ( !pData->isClosing )
  2282.         {
  2283.             Str255        wTitle;
  2284.             Cursor        arrow;
  2285.     
  2286.             pData->isClosing = true;
  2287.  
  2288.             GetWTitle(pWindow, wTitle);
  2289.             SetCursor(GetQDGlobalsArrow(&arrow));
  2290.             ParamText(wTitle, "\p", "\p", "\p");
  2291.             
  2292.             anErr = ConfirmSaveDialog( pWindow, wTitle, gMachineInfo.isQuitting, pData, &pData->navDialog );
  2293.             if ( anErr != noErr )
  2294.             {
  2295.                 pData->isClosing = false;
  2296.             }
  2297.         }
  2298.     }
  2299.     else
  2300.     {
  2301.         if ( (pData) && (pData->pCloseWindow) )
  2302.         {
  2303.             // let the object close the window if it wishes to
  2304.             anErr = (*(pData->pCloseWindow)) (pWindow, pData);
  2305.         }
  2306.  
  2307.         // otherwise we close it the default way
  2308.         if (anErr == noErr)
  2309.         {
  2310.             if (pData)
  2311.             {
  2312.                 // Close any Nav dialog that is running.
  2313.                 if ( pData->navDialog != NULL )
  2314.                 {
  2315.                     TerminateDialog( pData->navDialog );
  2316.                     pData->navDialog = NULL;
  2317.                 }
  2318.  
  2319.                 DisposeWindow(pWindow);
  2320.     
  2321.                 if (pData->hPageFormat)
  2322.                 {
  2323.                     DisposeHandle((Handle) pData->hPageFormat);
  2324.                     pData->hPageFormat = nil;
  2325.                 }
  2326.                 if (pData->hPrintSettings)
  2327.                 {
  2328.                     DisposeHandle((Handle) pData->hPrintSettings);
  2329.                     pData->hPrintSettings = nil;
  2330.                 }
  2331.                     
  2332.                 if (pData->resRefNum != -1)
  2333.                     CloseResFile(pData->resRefNum);
  2334.                 if (pData->dataRefNum != -1)
  2335.                     FSClose(pData->dataRefNum);
  2336.                 DisposePtr((Ptr) pData);
  2337.             }
  2338.         }
  2339.     }
  2340.  
  2341.     // If we closed the last window, clean up
  2342.     if (FrontWindow() == nil)
  2343.     {
  2344.         UnhiliteMenuDelayed(keyTime);        // unhilite before adjusting menus to avoid ugly menu title flashing
  2345.         AdjustMenus(nil, true, false);
  2346.         gMachineInfo.documentCount = 1;        // back to "untitled"
  2347.     }
  2348.     
  2349.     // make sure we update the cursor
  2350.     SetEmptyRgn(gCursorRgn);
  2351.     
  2352.     return anErr;
  2353.     
  2354. } // DoCloseWindow
  2355.  
  2356. // --------------------------------------------------------------------------------------------------------------
  2357. static OSStatus    DetermineWindowTypeOrOpen(
  2358.     FSSpecPtr theSpec, OSType theType,                 // optional input params -- file to open
  2359.     OSType *returnedTypeList, short * pNumTypes,    // optional input params -- returns list of files
  2360.     Boolean *pWasAlreadyOpen)                        // optional input params -- was file already open
  2361. {
  2362.     OSStatus    anErr = noErr;
  2363.     OSType        typeList[20];
  2364.     OSType        docList[20];
  2365.     short        numTypes;
  2366.  
  2367.     // use local copies if the input params are nil    
  2368.     if (returnedTypeList == nil)
  2369.         returnedTypeList = &typeList[0];
  2370.     if (pNumTypes == nil)
  2371.         pNumTypes = &numTypes;
  2372.     *pNumTypes = 0;
  2373.     
  2374.     // Load up all of the file types we know how to handle
  2375.     AboutGetFileTypes(returnedTypeList, docList, pNumTypes);
  2376.     PICTGetFileTypes(returnedTypeList, docList, pNumTypes);
  2377. #if ALLOW_QUICKTIME
  2378.     MovieGetFileTypes(returnedTypeList, docList, pNumTypes);
  2379. #endif
  2380.     ClipboardGetFileTypes(returnedTypeList, docList, pNumTypes);
  2381.     TextGetFileTypes(returnedTypeList, docList, pNumTypes);
  2382. #if ALLOW_QUICKTIME
  2383.     ThreeDGetFileTypes(returnedTypeList, docList, pNumTypes);
  2384. #endif
  2385.  
  2386.     if (theSpec != nil)
  2387.         {
  2388.         short         index;
  2389.         OSType        windowType = '????';
  2390.  
  2391.         for (index = 0; index < (*pNumTypes); ++index)
  2392.             if (theType == returnedTypeList[index])
  2393.                 windowType = docList[index];
  2394.         
  2395. #if ALLOW_QUICKTIME
  2396.         if (windowType == '????' && gMachineInfo.haveQuickTime)
  2397.             {
  2398.             ComponentDescription    ci;
  2399.             ci.componentType = GraphicsImporterComponentType;
  2400.             ci.componentSubType = theType;
  2401.             ci.componentManufacturer = kAnyComponentManufacturer;
  2402.             ci.componentFlags = 0;
  2403.             ci.componentFlagsMask = movieImportSubTypeIsFileExtension;
  2404.             if( 0 != FindNextComponent( 0, &ci ) )
  2405.             {
  2406.                 windowType = 'PICT';
  2407.             }
  2408.             }
  2409. #endif
  2410.         
  2411.         if (windowType != '????')
  2412.             {
  2413.             
  2414.             if ( (theType == 'TEXT') || (theType == 'sEXT') )
  2415.                 {
  2416.                 FInfo    theInfo;
  2417.                 
  2418.                 FSpGetFInfo(theSpec, &theInfo);
  2419.                 if ((theInfo.fdFlags & kIsStationery) != 0)
  2420.                     theType = 'sEXT';
  2421.                 else
  2422.                     theType = 'TEXT';
  2423.                 }
  2424.                 
  2425.             anErr = MakeNewWindow(windowType, theSpec, theType, pWasAlreadyOpen);
  2426.             }
  2427.         else
  2428.             anErr = eDocumentWrongKind;
  2429.         }
  2430.         
  2431.         
  2432.     return anErr;
  2433.     
  2434. } // DetermineWindowTypeOrOpen
  2435.  
  2436. // --------------------------------------------------------------------------------------------------------------
  2437. #if 0
  2438. // Handle update/activate events behind Standard File
  2439. static pascal Boolean OpenDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  2440.                                       short *itemHit, void *myDataPtr)
  2441. {
  2442.     #pragma unused(myDataPtr)
  2443.  
  2444.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  2445.     // drastically changing how the system handles the menu bar during our alert)
  2446.     if ( (theEvent->what == updateEvt) && (theEvent->message != (long)theDialog) )
  2447.         HandleEvent(theEvent);
  2448.  
  2449.     if (StdFilterProc(theDialog, theEvent, itemHit))
  2450.         return(true);
  2451.  
  2452.     return(false);
  2453.  
  2454. } // OpenDialogFilter
  2455. #endif
  2456.  
  2457. #if 0
  2458. #if GENERATINGCFM
  2459.     static RoutineDescriptor gOpenDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, OpenDialogFilter);
  2460.     static ModalFilterYDUPP gOpenDialogFilter = &gOpenDialogFilterRD;
  2461. #else
  2462.     static ModalFilterYDUPP gOpenDialogFilter = NewModalFilterYDProc(OpenDialogFilter);
  2463. #endif
  2464. #endif
  2465.  
  2466. static OSStatus DoOpenWindow(void)
  2467. {
  2468.     short                numTypes;
  2469.     OSType                typeList[20];
  2470.     OSType                fileType = '????';
  2471.     NavDialogRef        navDialog;
  2472.  
  2473.     DetermineWindowTypeOrOpen( nil, fileType, &typeList[0], &numTypes, nil );
  2474.     
  2475.     // Open as many documents as the user wishes through Appleevents
  2476.     return OpenFileDialog( 'ttxt', numTypes, typeList, &navDialog );
  2477. } // DoOpenWindow
  2478.  
  2479. // --------------------------------------------------------------------------------------------------------------
  2480. static OSStatus DoUpdateWindow(WindowPtr pWindow)
  2481. {
  2482.     OSStatus        anErr = noErr;
  2483.     WindowDataPtr    pData = GetWindowInfo(pWindow);
  2484.     GrafPtr            curPort;
  2485.     
  2486.     // only handle updates for windows we know about
  2487.     if (pData)
  2488.         {
  2489.         GetPort(&curPort);
  2490.         SetPortWindowPort (pWindow);
  2491.         BeginUpdate(pWindow);
  2492.                     
  2493.         if (pData->pUpdateWindow)
  2494.             anErr = (*(pData->pUpdateWindow)) (pWindow, pData);
  2495.     
  2496.         EndUpdate(pWindow);
  2497.         SetPort(curPort);
  2498.         }
  2499.     
  2500.     return anErr;
  2501.     
  2502. } // DoUpdateWindow
  2503.  
  2504. // --------------------------------------------------------------------------------------------------------------
  2505. OSStatus DoScrollContent(WindowPtr pWindow, WindowDataPtr pData, short deltaH, short deltaV)
  2506. {
  2507.     OSStatus    anErr = noErr;
  2508.     
  2509.     if ((deltaH) || (deltaV))
  2510.         {        
  2511.         if ((pData) && (pData->pScrollContent))
  2512.             anErr = (*(pData->pScrollContent)) (pWindow, pData, deltaH, deltaV);
  2513.             
  2514.         if (anErr == noErr)
  2515.             {
  2516.             RgnHandle    invalidRgn = NewRgn();
  2517.             
  2518.             ScrollRect(&pData->contentRect, deltaH, deltaV, invalidRgn);
  2519.             InvalWindowRgn(pWindow,invalidRgn);
  2520.             DisposeRgn(invalidRgn);
  2521.     
  2522.             (void) DoUpdateWindow(pWindow);
  2523.             }
  2524.         }
  2525.     
  2526.     return anErr;
  2527.     
  2528. } // DoScrollContent
  2529.  
  2530.  
  2531. // --------------------------------------------------------------------------------------------------------------
  2532. static OSStatus DoContentClick(WindowPtr pWindow)
  2533. {
  2534.     OSStatus            anErr = noErr;
  2535.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2536.     
  2537.     
  2538.     if ( pData )
  2539.         {
  2540.         SetPortWindowPort (pWindow);
  2541.         
  2542.         if (pData->pContentClick)
  2543.             {
  2544.             // let the object handle the click if it wishes to
  2545.             anErr = (*(pData->pContentClick)) (pWindow, pData, &gEvent);
  2546.             
  2547.             // invalidate the cursor rgn in case the object changed its appearance
  2548.             if (anErr != noErr)
  2549.                 SetEmptyRgn(gCursorRgn);
  2550.             }
  2551.         
  2552.         if (anErr == noErr) 
  2553.             {
  2554.             ControlHandle    theControl;
  2555.             short            part;
  2556.             
  2557.             GlobalToLocal(&gEvent.where);
  2558.             part = FindControl(gEvent.where, pWindow, &theControl);
  2559.             switch (part)
  2560.                 {
  2561.                 // do nothing for viewRect case
  2562.                 case 0:
  2563.                     break;
  2564.  
  2565.                 // track the thumb, and then update all at once
  2566.                 case kControlIndicatorPart:
  2567.                     {
  2568.                     short    value = GetControlValue(theControl);
  2569.                     
  2570.                     if (gMachineInfo.haveAppearanceMgr)
  2571.                         {
  2572.                         if (theControl == pData->hScroll)
  2573.                             {
  2574.                             pData->oldHValue = GetControlValue(theControl);
  2575.                             part = TrackControl(theControl, gEvent.where, gHActionProc);
  2576.                             }
  2577.                         if (theControl == pData->vScroll)
  2578.                             {
  2579.                             pData->oldVValue = GetControlValue(theControl);
  2580.                             part = TrackControl(theControl, gEvent.where, gVActionProc);
  2581.                             }
  2582.                         }
  2583.                     else
  2584.                         {
  2585.                         part = TrackControl(theControl, gEvent.where, nil);
  2586.                         if (part != 0)
  2587.                             {
  2588.                             // turn the value into a delta
  2589.                             value -= GetControlValue(theControl);
  2590.                             
  2591.                             // if we actually moved
  2592.                             if (value != 0)
  2593.                                 {
  2594.                                 if (theControl == pData->hScroll)
  2595.                                     DoScrollContent(pWindow, pData, value, 0);
  2596.                                 if (theControl == pData->vScroll)
  2597.                                     DoScrollContent(pWindow, pData, 0, value);
  2598.                                     
  2599.                                 }
  2600.                             }
  2601.                         }
  2602.                     }
  2603.                     break;
  2604.                     
  2605.                 // track the control, and scroll as we go
  2606.                 default:
  2607.                     if (theControl)
  2608.                     {
  2609.                         if (theControl == pData->hScroll)
  2610.                             part = TrackControl(theControl, gEvent.where, gHActionProc);
  2611.                         if (theControl == pData->vScroll)
  2612.                         {
  2613.                             gVScrollTrackStartTicks = TickCount();
  2614.                             gVScrollAccelerator = kVScrollAcceleratorIncrement;
  2615.                             part = TrackControl(theControl, gEvent.where, gVActionProc);
  2616.                         }
  2617.                     }
  2618.                     break;
  2619.                 }
  2620.             }
  2621.  
  2622.         }
  2623.  
  2624.         
  2625.     return anErr;
  2626.     
  2627. } // DoContentClick
  2628.  
  2629. // --------------------------------------------------------------------------------------------------------------
  2630. static OSStatus DoGrowWindow(WindowPtr pWindow, EventRecord *pEvent)
  2631. {
  2632.     OSStatus            anErr = noErr;
  2633.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2634.     Rect            tempRect;
  2635.     LongRect        docRect;
  2636.     long            growResult;
  2637.     
  2638.     if (pData)
  2639.         {
  2640.         SetPortWindowPort (pWindow);
  2641.         
  2642.         RectToLongRect(&pData->contentRect, &docRect);
  2643.         if (pData->pGetDocumentRect)
  2644.             (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true);
  2645.         if (pData->vScroll)
  2646.             docRect.right += 16;
  2647.         if (pData->hScroll)
  2648.             docRect.bottom += 16;
  2649.         
  2650.         if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  2651.             {
  2652.             docRect.right += 16;
  2653.             docRect.bottom += 16;
  2654.             }
  2655.             
  2656.         // set up resize constraints
  2657.         tempRect.left = pData->minHSize;
  2658.         if (tempRect.left == 0)
  2659.             tempRect.left = kMinDocSize;
  2660.         tempRect.right = docRect.right - docRect.left;
  2661.         if (tempRect.right < tempRect.left)
  2662.             tempRect.right = tempRect.left;
  2663.         tempRect.top = pData->minVSize;
  2664.         if (tempRect.top == 0)
  2665.             tempRect.top = kMinDocSize;
  2666.         tempRect.bottom = docRect.bottom - docRect.top;
  2667.         if (tempRect.bottom < tempRect.top)
  2668.             tempRect.bottom = tempRect.top;
  2669.             
  2670.         growResult = GrowWindow(pWindow, pEvent->where, &tempRect);
  2671.         if ( growResult != 0 ) 
  2672.             {
  2673.             Rect        oldRect;
  2674.             Boolean        needInvalidate;
  2675.             
  2676.             // save old content area
  2677.             oldRect = pData->contentRect;
  2678.             
  2679.             // grow window and recalc what is needed
  2680.             SizeWindow(pWindow, growResult & 0xFFFF, growResult >> 16, true);
  2681.             GetWindowPortBounds(pWindow, &pData->contentRect);
  2682.             AdjustScrollBars(pWindow, true, true, &needInvalidate);
  2683.             
  2684.             if (needInvalidate)
  2685.                 {
  2686.                 InvalWindowRect(pWindow, &pData->contentRect);
  2687.                 }
  2688.  
  2689.             // if we have offset scrollbars, then force a redraw of them
  2690.             if (pData->hScrollOffset)
  2691.                 {
  2692.                 GetWindowPortBounds(pWindow, &oldRect);
  2693.                 oldRect.right = oldRect.left + pData->hScrollOffset;
  2694.                 oldRect.top = oldRect.bottom - kScrollBarSize;
  2695.                 InvalWindowRect(pWindow,&oldRect);
  2696.                 }
  2697.             if (pData->vScrollOffset)
  2698.                 {
  2699.                 GetWindowPortBounds(pWindow, &oldRect);
  2700.                 oldRect.bottom = oldRect.top + pData->vScrollOffset;
  2701.                 oldRect.left = oldRect.right - kScrollBarSize;
  2702.                 InvalWindowRect(pWindow,&oldRect);
  2703.                 }
  2704.             }
  2705.             
  2706.         }
  2707.         
  2708.     
  2709.     return anErr;
  2710.     
  2711. } // DoGrowWindow
  2712.  
  2713. // --------------------------------------------------------------------------------------------------------------
  2714. static OSStatus DoZoomWindow(WindowPtr pWindow, short zoomDir)
  2715. {
  2716.     WindowDataPtr         pData = GetWindowInfo(pWindow);
  2717.     Rect                windRect, zoomRect;
  2718.     Rect                globalPortRect, theSect, dGDRect;
  2719.     GDHandle            nthDevice, dominantGDevice;
  2720.     long                sectArea, greatestArea;
  2721.     short                 hMax, vMax;
  2722.     Rect                bounds;
  2723.  
  2724.     // determine the max size of the window
  2725.     {
  2726.     WindowDataPtr            pData = GetWindowInfo(pWindow);
  2727.     LongRect            docRect;
  2728.     
  2729.     RectToLongRect(&pData->contentRect, &docRect);
  2730.     if (pData->pGetDocumentRect)
  2731.         (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true);
  2732.     if (pData->vScroll)
  2733.         docRect.right += kScrollBarSize;
  2734.     if (pData->hScroll)
  2735.         docRect.bottom += kScrollBarSize;
  2736.     
  2737.     if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) )
  2738.         {
  2739.         docRect.right += kScrollBarSize;
  2740.         docRect.bottom += kScrollBarSize;
  2741.         }
  2742.  
  2743.     hMax = docRect.right - docRect.left;
  2744.     vMax = docRect.bottom - docRect.top;
  2745.     }
  2746.  
  2747.     SetPortWindowPort (pWindow);
  2748.     GetWindowPortBounds(pWindow, &bounds);
  2749.     EraseRect(&bounds);    // recommended for cosmetic reasons
  2750.  
  2751.     if (zoomDir == inZoomOut) 
  2752.         {
  2753.  
  2754.         /*
  2755.          *    ZoomWindow() is a good basic tool, but it doesn't do everything necessary to
  2756.          *    implement a good human interface when zooming. In fact it's not even close for
  2757.          *    more high-end hardware configurations. We must help it along by calculating an
  2758.          *    appropriate window size and location any time a window zooms out.
  2759.          */
  2760.         {
  2761.         RgnHandle    structRgn = NewRgn();
  2762.         
  2763.         GetWindowRegion(pWindow, kWindowStructureRgn, structRgn);
  2764.  
  2765.         GetRegionBounds( structRgn, &windRect);
  2766.  
  2767.         DisposeRgn(structRgn);
  2768.         }
  2769.         dominantGDevice = nil;
  2770.  
  2771.         /*
  2772.          *    Color QuickDraw implies the possibility of multiple monitors. This is where
  2773.          *    zooming becomes more interesting. One should zoom onto the monitor containing
  2774.          *    the greatest portion of the window. This requires walking the gDevice list.
  2775.          */
  2776.  
  2777.         nthDevice = GetDeviceList();
  2778.         greatestArea = 0;
  2779.         while (nthDevice != nil) 
  2780.             {
  2781.             if (TestDeviceAttribute(nthDevice, screenDevice)) 
  2782.                 {
  2783.                 if (TestDeviceAttribute(nthDevice, screenActive)) 
  2784.                     {
  2785.                     SectRect(&windRect, &(**nthDevice).gdRect, &theSect);
  2786.                     sectArea = (long) RectWidth(theSect) * (long) RectHeight(theSect);
  2787.                     if (sectArea > greatestArea) 
  2788.                         {
  2789.                         greatestArea = sectArea;        // save the greatest intersection
  2790.                         dominantGDevice = nthDevice;    // and which device it belongs to
  2791.                         }
  2792.                     }
  2793.                 }
  2794.             nthDevice = GetNextDevice(nthDevice);
  2795.             }
  2796.  
  2797.         /*
  2798.          *    At this point, we know the dimensions of the window we're zooming, and we know
  2799.          *    what screen we're going to put it on. To be more specific, however, we need a
  2800.          *    rectangle which defines the maximum dimensions of the resized window's contents.
  2801.          *    This rectangle accounts for the thickness of the window frame, the menu bar, and
  2802.          *    one or two pixels around the edges for cosmetic compatibility with ZoomWindow().
  2803.          */
  2804.  
  2805.         if (dominantGDevice != nil) 
  2806.             {
  2807.             dGDRect = (**dominantGDevice).gdRect;
  2808.             if (dominantGDevice == GetMainDevice())        // account for menu bar on main device
  2809.                 dGDRect.top += GetMBarHeight();
  2810.             }
  2811.         else 
  2812.             {
  2813.             BitMap bitmap;
  2814.                         GetQDGlobalsScreenBits(&bitmap);
  2815.                         dGDRect = bitmap.bounds
  2816. ;    // if no gDevice, use default monitor
  2817.             dGDRect.top += GetMBarHeight();
  2818.             }
  2819.  
  2820.         GetWindowPortBounds(pWindow, &globalPortRect);
  2821.         LocalToGlobal(&TopLeft(globalPortRect));        // calculate the window's portRect
  2822.         LocalToGlobal(&BotRight(globalPortRect));        // in global coordinates
  2823.  
  2824.         // account for the window frame and inset it a few pixels
  2825.         dGDRect.left    += 2 + globalPortRect.left - windRect.left;
  2826.         dGDRect.top        += 2 + globalPortRect.top - windRect.top;
  2827.         dGDRect.right    -= 1 + windRect.right - globalPortRect.right;
  2828.         dGDRect.bottom    -= 1 + windRect.bottom - globalPortRect.bottom;
  2829.  
  2830.         /*
  2831.          *    Now we know exactly what our limits are, and since there are input parameters
  2832.          *    specifying the dimensions we'd like to see, we can move and resize the zoom
  2833.          *    state rectangle for the best possible results. We have three goals in this:
  2834.          *    1. Display the window entirely visible on a single device.
  2835.          *    2. Resize the window to best represent the dimensions of the document itself.
  2836.          *    3. Move the window as short a distance as possible to achieve #1 and #2.
  2837.          */
  2838.  
  2839.         //zoomRect = &(**(WStateDataHandle) ((WindowPeek) pWindow)->dataHandle).stdState;
  2840.                 GetWindowIdealUserState(pWindow, &zoomRect);                
  2841.         /*
  2842.          *    Initially set the zoom rectangle to the size requested by the input parameters,
  2843.          *    although not smaller than a minimum size. We do this without moving the origin.
  2844.          */
  2845.  
  2846.         zoomRect.right = (zoomRect.left = globalPortRect.left) +
  2847.                                 Max(hMax, kMinDocSize);
  2848.         zoomRect.bottom = (zoomRect.top = globalPortRect.top) +
  2849.                                 Max(vMax, kMinDocSize);
  2850.  
  2851.         // Shift the entire rectangle if necessary to bring its origin inside dGDRect.
  2852.         OffsetRect(&zoomRect,
  2853.                     Max(dGDRect.left - zoomRect.left, 0),
  2854.                     Max(dGDRect.top - zoomRect.top, 0));
  2855.  
  2856.         /*
  2857.          *    Shift the rectangle up and/or to the left if necessary to accomodate the view,
  2858.          *    and if it is possible to do so. The rectangle may not be moved such that its
  2859.          *    origin would fall outside of dGDRect.
  2860.          */
  2861.  
  2862.         OffsetRect(&zoomRect,
  2863.                     -Pin(zoomRect.right - dGDRect.right, 0, zoomRect.left - dGDRect.left),
  2864.                     -Pin(zoomRect.bottom - dGDRect.bottom, 0, zoomRect.top - dGDRect.top));
  2865.  
  2866.         // Clip expansion to dGDRect, in case view is larger than dGDRect.
  2867.         zoomRect.right = Min(zoomRect.right, dGDRect.right);
  2868.         zoomRect.bottom = Min(zoomRect.bottom, dGDRect.bottom);
  2869.  
  2870.                 SetWindowIdealUserState(pWindow, &zoomRect);
  2871.         }
  2872.  
  2873.     ZoomWindow(pWindow, zoomDir, pWindow == FrontWindow());
  2874.     
  2875.     GetWindowPortBounds(pWindow, &pData->contentRect);
  2876.     AdjustScrollBars(pWindow, true, true, nil);
  2877.  
  2878.     InvalWindowRect(pWindow, &pData->contentRect);
  2879.     
  2880.     return noErr;
  2881.     
  2882. } // DoZoomWindow
  2883.  
  2884. // --------------------------------------------------------------------------------------------------------------
  2885. OSStatus DoActivate(WindowPtr pWindow, Boolean activating)
  2886. {
  2887.  
  2888.     OSStatus            anErr = noErr;
  2889.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2890.  
  2891.     SetPortWindowPort (pWindow);
  2892.     
  2893.     if ( pData )
  2894.     {
  2895.         if (pData->pActivateEvent)
  2896.         {
  2897.             anErr = (*(pData->pActivateEvent)) (pWindow, pData, activating);
  2898.         }
  2899.     
  2900.         if (anErr == noErr)
  2901.         {
  2902.             if (activating)
  2903.             {
  2904.                 if (pData->hScroll)
  2905.                     HiliteControl( pData->hScroll, 0 );
  2906.                 if (pData->vScroll)
  2907.                     HiliteControl( pData->vScroll, 0 );
  2908.             }
  2909.             else
  2910.             {
  2911.                 if (pData->hScroll)
  2912.                     HiliteControl( pData->hScroll, kControlDisabledPart );
  2913.                 if (pData->vScroll)
  2914.                     HiliteControl( pData->vScroll, kControlDisabledPart );
  2915.             }
  2916.             
  2917.             
  2918.             if ( pData->hasGrow )
  2919.             {
  2920.                 Rect    growIconRect;
  2921.                 
  2922.                 CalculateGrowIcon(pWindow,pData, &growIconRect);
  2923.                 InvalWindowRect(pWindow,&growIconRect);
  2924.             }
  2925.         }
  2926.     }
  2927.  
  2928.     if ( activating )
  2929.         AdjustMenus(pWindow, true, false);
  2930.         
  2931.     return anErr;
  2932.     
  2933. } // DoActivate
  2934.  
  2935. OSStatus DoDefault(WindowDataPtr pData) {
  2936.     OSStatus anErr = noErr;
  2937.  
  2938.     OSStatus status;
  2939.  
  2940.     status = PMBegin();
  2941.     
  2942.     // create default page format
  2943.     if ((status == noErr) && (pData->hPageFormat == nil))
  2944.     {
  2945.         PMPageFormat pageFormat = kPMNoPageFormat;
  2946.  
  2947.         status = PMNewPageFormat(&pageFormat);
  2948.         if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  2949.             status = PMDefaultPageFormat(pageFormat);
  2950.  
  2951.         if (status == noErr)
  2952.             status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat);
  2953.  
  2954.         if (pageFormat != kPMNoPageFormat)
  2955.             (void)PMDisposePageFormat(pageFormat);
  2956.     }
  2957.  
  2958.     // create default print settings
  2959.     if ((status == noErr) && (pData->hPrintSettings == nil))
  2960.     {
  2961.         PMPrintSettings printSettings = kPMNoPrintSettings;
  2962.  
  2963.         status = PMNewPrintSettings(&printSettings);
  2964.         if ((status == noErr) && (printSettings != kPMNoPrintSettings))
  2965.             status = PMDefaultPrintSettings(printSettings);
  2966.  
  2967.         if (status == noErr)
  2968.             status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings);
  2969.  
  2970.         if (printSettings != kPMNoPrintSettings)
  2971.             (void)PMDisposePrintSettings(printSettings);
  2972.  
  2973.     }
  2974.     (void)PMEnd();
  2975.  
  2976.     anErr = (OSStatus)status;
  2977.     
  2978.     return anErr;
  2979. }
  2980.  
  2981. // --------------------------------------------------------------------------------------------------------------
  2982. OSStatus    DoPageSetup(WindowPtr pWindow)
  2983. {
  2984.     OSStatus            anErr = noErr;
  2985.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  2986.     Boolean         accepted;
  2987.         
  2988.     anErr = DoDefault(pData);
  2989.     nrequire(anErr, DoDefault);
  2990.     
  2991.     if (pData->hPageFormat != nil)
  2992.     {
  2993.         OSStatus status;
  2994.  
  2995.         status = PMBegin();
  2996.         if (status == noErr)
  2997.         {
  2998.             PMPageFormat pageFormat = kPMNoPageFormat;
  2999.  
  3000.             // retrieve the default page format
  3001.             status = PMUnflattenPageFormat(pData->hPageFormat, &pageFormat);
  3002.  
  3003.             if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  3004.             {
  3005.                 Cursor arrow;
  3006.  
  3007.                 SetCursor(GetQDGlobalsArrow(&arrow));
  3008.                 status = PMPageSetupDialog(pageFormat, &accepted);
  3009.                 if (!accepted)
  3010.                     status = kPMCancel;
  3011.             }
  3012.  
  3013.             // save any changes to the page format
  3014.             if (status == noErr && accepted) {
  3015.                 DisposeHandle( pData->hPageFormat );
  3016.                 pData->hPageFormat = nil;
  3017.                 status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat);
  3018.  
  3019.             }
  3020.             if (pageFormat != kPMNoPageFormat)
  3021.                 (void)PMDisposePageFormat(pageFormat);
  3022.         }
  3023.         (void)PMEnd();
  3024.  
  3025.         anErr = (OSStatus)status;
  3026.     }
  3027.  
  3028. // FALL THROUGH EXCEPTION HANDLING
  3029. DoDefault:        
  3030.     return anErr;
  3031.     
  3032. } // DoPageSetup
  3033.  
  3034. // --------------------------------------------------------------------------------------------------------------
  3035. static OSStatus    DoPrintSetup(WindowPtr pWindow, StringPtr pPrinterName)
  3036. {
  3037. #pragma unused (pPrinterName)
  3038.  
  3039.     OSStatus            anErr = noErr;
  3040.     WindowDataPtr     pData = GetWindowInfo(pWindow);
  3041.     Boolean         accepted;
  3042.         
  3043.     anErr = DoDefault(pData);
  3044.     nrequire(anErr, DoDefault);
  3045.     
  3046.     if ((pData->hPrintSettings != nil) && (pData->hPageFormat != nil))
  3047.     {
  3048.         OSStatus status;
  3049.  
  3050.         status = PMBegin();
  3051.         if (status == noErr)
  3052.         {
  3053.             PMPrintSettings printSettings = kPMNoPrintSettings;
  3054.             PMPageFormat pageFormat = kPMNoPageFormat;
  3055.  
  3056.             // retrieve the default printing objects
  3057.             status = PMUnflattenPageFormat(pData->hPageFormat, &pageFormat);
  3058.             if (status == noErr)
  3059.                 status = PMUnflattenPrintSettings(pData->hPrintSettings, &printSettings);
  3060.  
  3061.             if ((status == noErr) && (printSettings != kPMNoPrintSettings) && (pageFormat != kPMNoPageFormat))
  3062.             {
  3063.                 Cursor arrow;
  3064.                 SetCursor(GetQDGlobalsArrow(&arrow));
  3065.  
  3066.                 status = PMPrintDialog(printSettings, pageFormat, &accepted );
  3067.                 if (!accepted)
  3068.                     status = eUserCanceled;
  3069.             }
  3070.  
  3071.             if (status == noErr && accepted)
  3072.             {
  3073.                 // replace with the new print settings handle
  3074.                 // NOTE:  the pageFormat object does not get modified
  3075.                 DisposeHandle(pData->hPrintSettings);
  3076.                 pData->hPrintSettings = nil;
  3077.                 status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings);
  3078.             }
  3079.  
  3080.             if (printSettings != kPMNoPrintSettings)
  3081.                 (void)PMDisposePrintSettings(printSettings);
  3082.         }
  3083.         (void)PMEnd();
  3084.  
  3085.         anErr = (OSStatus)status;
  3086.     }
  3087.         
  3088. // FALL THROUGH EXCEPTION HANDLING
  3089. DoDefault:        
  3090.     return anErr;
  3091.     
  3092. } // DoPrintSetup
  3093.  
  3094. // --------------------------------------------------------------------------------------------------------------
  3095. static OSStatus    DoPrint(WindowPtr pWindow, void * hPageFormat, void * hPrintSettings, Boolean oneCopy)
  3096. {
  3097.     WindowDataPtr         pData = GetWindowInfo(pWindow);
  3098.  
  3099.         OSStatus status;
  3100.         PMPageFormat pageFormat = kPMNoPageFormat;
  3101.         PMPrintSettings printSettings = kPMNoPrintSettings;
  3102.         PMPrintContext thePrintingPort = kPMNoReference;
  3103.         
  3104.         status = PMBegin();
  3105.         if (status == noErr)
  3106.         {
  3107.             if (hPageFormat != nil)
  3108.             {
  3109.                 status = PMUnflattenPageFormat(hPageFormat, &pageFormat);
  3110.             }
  3111.             else
  3112.             {
  3113.                 status = PMNewPageFormat(&pageFormat);
  3114.                 if ((status == noErr) && (pageFormat != kPMNoPageFormat))
  3115.                     status = PMDefaultPageFormat(pageFormat);
  3116.             }
  3117.             if (hPrintSettings != nil)
  3118.             {
  3119.                 status = PMUnflattenPrintSettings(hPrintSettings, &printSettings);
  3120.             }
  3121.             else
  3122.             {
  3123.                 status = PMNewPrintSettings(&printSettings);
  3124.                 if ((status == noErr) && (printSettings != kPMNoPrintSettings))
  3125.                     status = PMDefaultPrintSettings(printSettings);
  3126.             }
  3127.         }
  3128.  
  3129.         if (status == noErr)
  3130.         {
  3131.             long    pageIndex;
  3132.             UInt32    firstPage, lastPage;
  3133.             
  3134.             // be sure to get the page range BEFORE calling PrValidate(), 
  3135.             // which blows it away for many drivers.
  3136.             status = PMGetFirstPage(printSettings, &firstPage);
  3137.             if (status == noErr)
  3138.                 status = PMGetLastPage(printSettings, &lastPage);
  3139.  
  3140.             if (status == noErr)
  3141.                 status = PMValidatePrintSettings(printSettings, kPMDontWantBoolean);
  3142.  
  3143.              status = PMGetFirstPage(printSettings, &firstPage);
  3144.             if (status == noErr)
  3145.                 status = PMGetLastPage(printSettings, &lastPage);
  3146.  
  3147.            if (status == noErr)
  3148.                 status = PMSetFirstPage(printSettings, 1, true);
  3149.             if (status == noErr)
  3150.                 status = PMSetLastPage(printSettings, 9999, true);
  3151.  
  3152.            if ((status == noErr) && (oneCopy))
  3153.                 status = PMSetCopies(printSettings, 1, true);
  3154.  
  3155.             if (status == noErr)
  3156.             {
  3157.                 Rect    pageRect;
  3158.                 
  3159.                 status = PMBeginDocument(printSettings, pageFormat, &thePrintingPort);
  3160.                 if ((status == noErr) && (thePrintingPort != kPMNoReference))
  3161.                 {
  3162.                     PMRect  tempPageRect;
  3163.                     status = PMGetAdjustedPageRect(pageFormat, &tempPageRect);
  3164.                     if (status == noErr)
  3165.                     {
  3166.                         pageRect.top = tempPageRect.top;
  3167.                         pageRect.left = tempPageRect.left;
  3168.                         pageRect.bottom = tempPageRect.bottom;
  3169.                         pageRect.right = tempPageRect.right;
  3170.  
  3171.                 if (firstPage < 1)
  3172.                     firstPage = 1;
  3173.                 if (lastPage < firstPage)
  3174.                     lastPage = firstPage;
  3175.                 for (pageIndex = firstPage; pageIndex <= lastPage; ++pageIndex)
  3176.                     {
  3177.                             status = PMBeginPage(thePrintingPort, nil);
  3178.                             if (status == noErr)
  3179.                                 status = (OSStatus)(*(pData->pPrintPage)) (pWindow, pData, &pageRect, &pageIndex);
  3180.  
  3181.                             status = PMEndPage(thePrintingPort);
  3182.                             if ((status != noErr) || (pageIndex == -1))
  3183.                                 break;
  3184.                         }
  3185.                     }
  3186.  
  3187.                     (void)PMEndDocument(thePrintingPort);
  3188.                 }
  3189.             }
  3190.         }
  3191.  
  3192.         if (printSettings != kPMNoPrintSettings)
  3193.             (void)PMDisposePrintSettings(printSettings);
  3194.         if (pageFormat != kPMNoPageFormat)
  3195.             (void)PMDisposePageFormat(pageFormat);
  3196.         
  3197.         (void)PMEnd();
  3198.  
  3199.         return (OSStatus)status;
  3200.     
  3201. } // DoPrint
  3202.  
  3203.  
  3204. static OSStatus DoQuit()
  3205. {
  3206.     OSStatus    status;
  3207.     UInt32        dirtyCount = 0;
  3208.     WindowPtr    pWindow, nextWindow, dirtyWindow;
  3209.  
  3210.     if ( !gMachineInfo.isQuitting )
  3211.     {
  3212.         gMachineInfo.isQuitting = true;
  3213.     
  3214.         // See how many unsaved windows there are
  3215.         pWindow = FrontWindow();
  3216.         while ( (pWindow != NULL) && dirtyCount < 2 )
  3217.         {
  3218.             nextWindow = GetNextWindow(pWindow);
  3219.             if ( !CanCloseWindow( pWindow ))
  3220.             {
  3221.                 dirtyWindow = pWindow;
  3222.                 dirtyCount++;
  3223.             }
  3224.             pWindow = nextWindow;
  3225.         }    
  3226.         
  3227.         if ( dirtyCount == 1 )
  3228.         {
  3229.             Str255             wTitle;
  3230.             NavDialogRef    navDialog;
  3231.             WindowDataPtr    pData = GetWindowInfo( dirtyWindow );
  3232.     
  3233.             GetWTitle( dirtyWindow, wTitle);
  3234.             ParamText( wTitle, "\p", "\p", "\p" );
  3235.             if ( pData )
  3236.             {
  3237.                 pData->isClosing = true;
  3238.             }
  3239.             // Call the confirm save for the document, but present it app-modal
  3240.             // by passing a NULL parent window
  3241.             status = ConfirmSaveDialog( NULL, wTitle, true, pData, &navDialog );
  3242.             if ( status != noErr )
  3243.             {
  3244.                 gMachineInfo.isQuitting = false;
  3245.                 if ( pData )
  3246.                 {
  3247.                     pData->isClosing = false;
  3248.                 }
  3249.             }
  3250.         }
  3251.         else if ( dirtyCount > 1 )
  3252.         {
  3253.             NavUserAction    userAction = kNavUserActionNone;
  3254.             status = ModalConfirmSaveDialog( NULL, true, &userAction );
  3255.             if ( status != noErr || userAction == kNavUserActionCancel )
  3256.             {
  3257.                 gMachineInfo.isQuitting = false;
  3258.             }
  3259.         }
  3260.     }
  3261.  
  3262.     // Still quitting after (possibly) running the modal confirm dialog?
  3263.     if ( gMachineInfo.isQuitting )
  3264.     {
  3265.         // Close the clean documents, others will be confirmed one by one.
  3266.         CloseAllWindows( false );        
  3267.     }
  3268.  
  3269.     return noErr;
  3270. }
  3271.  
  3272.  
  3273. // --------------------------------------------------------------------------------------------------------------
  3274. OSStatus DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime)
  3275. {
  3276.     OSStatus        anErr = noErr;
  3277.     WindowDataPtr     pData = nil;
  3278.     
  3279.     if (pWindow)
  3280.         {
  3281.         pData = (WindowDataPtr) GetWindowInfo(pWindow);
  3282.         
  3283.         if ( (pData) && (pData->pCommand) )
  3284.             anErr = (*(pData->pCommand)) (pWindow, pData, commandID, menuResult);
  3285.         }
  3286.     
  3287.     if (anErr == noErr)
  3288.         {
  3289.         // default command handling
  3290.         switch (commandID)
  3291.             {
  3292. #if !SIMPLER_TEXT
  3293.             // About box command
  3294.             case cAbout:
  3295.                 if (!BringToFrontIfExists(kAboutWindow))
  3296.                     anErr = MakeNewWindow(kAboutWindow, nil, '????', nil);
  3297.                 break;
  3298. #endif
  3299. #if(0)                
  3300.             case cDeskAccessory:
  3301.                 {
  3302.                 Str255    tempString;
  3303.                 
  3304.                 GetMenuItemText(GetMenuHandle(menuResult>>16), menuResult & 0xFFFF, tempString);
  3305.                 OpenDeskAcc(tempString);
  3306.                 }
  3307.                 break;
  3308. #endif                
  3309.             // New window command
  3310.             case cNew:
  3311.                 anErr = MakeNewWindow(kTextWindow, nil, 'TEXT', nil);
  3312.                 break;
  3313.                 
  3314.             // Open window command
  3315.             case cOpen:
  3316.                 anErr = DoOpenWindow();
  3317.                 break;
  3318.                 
  3319.             // Close window command
  3320.             case cClose:
  3321.                 anErr = DoCloseWindow(pWindow, false, keyTime);
  3322.                 break;
  3323.  
  3324. #if !SIMPLER_TEXT
  3325.             case cPageSetup:
  3326.                 anErr = DoPageSetup(pWindow);
  3327.                 break;
  3328.  
  3329.             case cPrint:
  3330.                 anErr = DoPrintSetup(pWindow, nil);
  3331.                 if (anErr == noErr)
  3332.                     anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false);
  3333.                 break;
  3334.                 
  3335.             case cPrintOneCopy:
  3336.                 anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, true);
  3337.                 break;
  3338. #endif                
  3339.             // get out of here command!
  3340.             case cQuit:
  3341.                 anErr = DoQuit();
  3342.                 break;
  3343.     
  3344.             // show/hide clipboard
  3345.             case cShowClipboard:
  3346.                 if (!BringToFrontIfExists(kClipboardWindow))
  3347.                     {
  3348.                     anErr = MakeNewWindow(kClipboardWindow, nil, '????', nil);
  3349.                     }
  3350.                 else
  3351.                     {
  3352.                     pWindow = FrontWindow();
  3353.                     anErr = DoCloseWindow(pWindow, false, keyTime);
  3354.                     }
  3355.                 break;
  3356.                 
  3357.             case cNextPage:
  3358.                 gEvent.what = keyDown;
  3359.                 gEvent.message = kPageDown << 8;
  3360.                 gEvent.modifiers = 0;
  3361.                 DoKeyEvent(pWindow, &gEvent, false);
  3362.                 break;
  3363.                 
  3364.             case cPreviousPage:
  3365.                 gEvent.what = keyDown;
  3366.                 gEvent.message = kPageUp << 8;
  3367.                 gEvent.modifiers = 0;
  3368.                 DoKeyEvent(pWindow, &gEvent, false);
  3369.                 break;
  3370.                 
  3371.             // Do nothing command
  3372.             case cNull:
  3373.                 break;
  3374.                             
  3375.             default:
  3376.                 break;
  3377.             }
  3378.         }
  3379.         
  3380.     // don't report cancels
  3381.     if (anErr == kPMCancel)
  3382.         anErr = noErr;
  3383.     
  3384.     if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) )
  3385.         {
  3386.         // some commands are so similar to other commands that we map their IDs
  3387.         // for the purposes of the error strings
  3388.         if (commandID == cSaveAs)
  3389.             commandID = cSave;
  3390.         if (commandID == cPrintOneCopy)
  3391.             commandID = cPrint;
  3392.             
  3393.         ConductErrorDialog(anErr, commandID, cancel);
  3394.         }
  3395.         
  3396.     // in any case, unhilite the menu selected after command processing is done,
  3397.     // but first delay for a short while if the command was invoked via a cmd key
  3398.     // so that the menu title is hilighted long enough for the user to see it
  3399.     UnhiliteMenuDelayed(keyTime);
  3400.     
  3401.     return anErr;
  3402.     
  3403. } // DoCommand
  3404.  
  3405. // --------------------------------------------------------------------------------------------------------------
  3406. static OSStatus    DoMenuCommand(WindowPtr pWindow, long menuResult, long keyTime)
  3407. {
  3408.     OSStatus    anErr = noErr;
  3409.     short    commandID = cNull;
  3410.     short    ** commandHandle;
  3411.     short    menuID = menuResult >> 16;
  3412.  
  3413.     if (menuID >= mFontSubMenusStart)
  3414.         {
  3415.         commandID = cSelectFontStyle;
  3416.         }
  3417.     else
  3418.         {
  3419.         // read in the resource that controls this menu
  3420.             {
  3421.             short    oldResFile = CurResFile();
  3422.             
  3423.             UseResFile(gApplicationResFile);
  3424.             commandHandle = (short**) Get1Resource('MCMD', menuID);
  3425.             UseResFile(oldResFile);
  3426.             anErr = ResError();
  3427.             nrequire(anErr, FailedToLoadCommandTable);
  3428.             }
  3429.         
  3430.         if (commandHandle)
  3431.             {
  3432.             short    item = menuResult & 0xFFFF;
  3433.             short    * pCommands = *commandHandle;
  3434.             
  3435.             if (item <= pCommands[0])
  3436.                 commandID = pCommands[item];
  3437.             else
  3438.                 commandID = pCommands[pCommands[0]];
  3439.             }
  3440.         }
  3441.     
  3442.     anErr = DoCommand(pWindow, commandID, menuResult, keyTime);
  3443.     
  3444. // FALL THROUGH EXCEPTION HANDLING
  3445. FailedToLoadCommandTable:
  3446.  
  3447.     return anErr;
  3448.     
  3449. } // DoMenuCommand
  3450.  
  3451.  
  3452. // --------------------------------------------------------------------------------------------------------------
  3453. static void DoKeyPageDown(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls)
  3454. {
  3455.  
  3456.     if (GetControlValue(pData->vScroll) < GetControlMaximum(pData->vScroll))
  3457.         VActionProc(pData->vScroll, kControlPageDownPart);
  3458.     else
  3459.         {
  3460.         if ( (processPageControls) && (IsCommandEnabled(cNextPage)) )
  3461.             {
  3462.             short amount;
  3463.  
  3464.             if (DoCommand(pWindow, cNextPage, 0, 0) == eActionAlreadyHandled)
  3465.                 {
  3466.                 amount = GetControlValue(pData->vScroll);
  3467.                 SetControlAndClipAmount(pData->vScroll, &amount);
  3468.                 if (amount != 0)
  3469.                     DoScrollContent(pWindow, pData, 0, amount);
  3470.                 }
  3471.             
  3472.             AdjustMenus(pWindow, true, false);
  3473.             }
  3474.         }
  3475.     
  3476. } // DoKeyPageDown
  3477.  
  3478. // --------------------------------------------------------------------------------------------------------------
  3479. static void DoKeyPageUp(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls)
  3480. {
  3481.     if (GetControlValue(pData->vScroll) > GetControlMinimum(pData->vScroll))
  3482.         VActionProc(pData->vScroll, kControlPageUpPart);
  3483.     else
  3484.         {
  3485.         if ( (processPageControls) && (IsCommandEnabled(cPreviousPage)) )
  3486.             {
  3487.             short amount;
  3488.             
  3489.             if (DoCommand(pWindow, cPreviousPage, 0, 0) == eActionAlreadyHandled)
  3490.                 {
  3491.                 amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll));
  3492.                 SetControlAndClipAmount(pData->vScroll, &amount);
  3493.                 if (amount != 0)
  3494.                     DoScrollContent(pWindow, pData, 0, amount);
  3495.                 }
  3496.             
  3497.             AdjustMenus(pWindow, true, false);
  3498.             }
  3499.         }
  3500.         
  3501. } // DoKeyPageUp
  3502.  
  3503. // --------------------------------------------------------------------------------------------------------------
  3504. OSStatus    DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls)
  3505. {
  3506.     OSStatus            anErr = noErr;
  3507.     WindowDataPtr     pData = nil;
  3508.     Boolean            passToObject = false;
  3509.     Boolean         isMotionKey = false;
  3510.     long            menuResult = 0;
  3511.     
  3512.     char keyCode = (pEvent->message >> 8) & charCodeMask;
  3513.  
  3514.     if (pWindow)
  3515.         pData = GetWindowInfo(pWindow);
  3516.     
  3517.     if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3518.         {
  3519.         if ( (pData) && (pData->pPreMenuAccess) )
  3520.             (void) (*(pData->pPreMenuAccess)) (pWindow, pData);
  3521.         AdjustMenus(pWindow, true, false);
  3522.         menuResult = MenuKey(pEvent->message & charCodeMask);
  3523.         DoMenuCommand(pWindow, menuResult, TickCount());
  3524.         pWindow = FrontWindow();
  3525.         }
  3526.  
  3527.     if (menuResult == 0)
  3528.         {
  3529.         if (pWindow)
  3530.             {
  3531.             if ( (pData) && (pData->pKeyEvent) )
  3532.                 passToObject = true;
  3533.             SetPortWindowPort (pWindow);
  3534.             }
  3535.             
  3536.         if (pData)
  3537.             {
  3538.             switch (keyCode)
  3539.                 {
  3540.                 case kHome: // top of file
  3541.                     isMotionKey = true;
  3542.                     if (pData->vScroll)
  3543.                         {
  3544.                         short amount;
  3545.                         
  3546.                         if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) )
  3547.                             DoCommand(pWindow, cGotoPage, cGotoFirst, 0);
  3548.  
  3549.                         amount = GetControlValue(pData->vScroll);
  3550.                         SetControlAndClipAmount(pData->vScroll, &amount);
  3551.                         if (amount != 0)
  3552.                             DoScrollContent(pWindow, pData, 0, amount);
  3553.                         passToObject = false;
  3554.                         }
  3555.                     break;
  3556.                     
  3557.                 case kEnd: // end of file
  3558.                     isMotionKey = true;
  3559.                     if (pData->vScroll)
  3560.                         {
  3561.                         short amount;
  3562.  
  3563.                         if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) )
  3564.                             DoCommand(pWindow, cGotoPage, cGotoLast, 0);
  3565.                             
  3566.                         amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll));
  3567.                         SetControlAndClipAmount(pData->vScroll, &amount);
  3568.                         if (amount != 0)
  3569.                             DoScrollContent(pWindow, pData, 0, amount);
  3570.                         passToObject = false;
  3571.                         }
  3572.                     break;
  3573.                     
  3574.                 case kPageUp: // scroll bar page up
  3575.                     isMotionKey = true;
  3576.                     if (pData->vScroll)
  3577.                         {
  3578.                         DoKeyPageUp(pWindow, pData, processPageControls);
  3579.                         passToObject = false;
  3580.                         }
  3581.                     break;
  3582.                     
  3583.                 case kPageDown: // scroll bar page down
  3584.                     isMotionKey = true;
  3585.                     if (pData->vScroll)
  3586.                         {
  3587.                         DoKeyPageDown(pWindow, pData, processPageControls);
  3588.                         passToObject = false;
  3589.                         }
  3590.                     break;
  3591.                             
  3592.                 case kUpArrow:        // scroll bar up arrow
  3593.                     isMotionKey = true;
  3594.                     if ( (pData->vScroll) && (!pData->pKeyEvent) )
  3595.                         {
  3596.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3597.                             DoKeyPageUp(pWindow, pData, processPageControls);
  3598.                         else
  3599.                             VActionProc(pData->vScroll, kControlUpButtonPart);
  3600.                         passToObject = false;
  3601.                         }
  3602.                     break;
  3603.                     
  3604.                 case kDownArrow:    // scroll bar down arrow
  3605.                     isMotionKey = true;
  3606.                     if ( (pData->vScroll) && (!pData->pKeyEvent) )
  3607.                         {
  3608.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3609.                             DoKeyPageDown(pWindow, pData, processPageControls);
  3610.                         else
  3611.                             VActionProc(pData->vScroll, kControlDownButtonPart);
  3612.                         passToObject = false;
  3613.                         }
  3614.                     break;
  3615.         
  3616.                 case kLeftArrow:    // scroll bar left arrow
  3617.                     isMotionKey = true;
  3618.                     if ( (pData->hScroll) && (!pData->pKeyEvent) )
  3619.                         {
  3620.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3621.                             HActionProc(pData->hScroll, kControlPageUpPart);
  3622.                         else
  3623.                             HActionProc(pData->hScroll, kControlUpButtonPart);
  3624.                         passToObject = false;
  3625.                         }
  3626.                     break;
  3627.                     
  3628.                 case kRightArrow:    // scroll bar right arrow
  3629.                     isMotionKey = true;
  3630.                     if ( (pData->hScroll) && (!pData->pKeyEvent) )
  3631.                         {
  3632.                         if ( pEvent->modifiers & cmdKey )            /* Command key down */
  3633.                             HActionProc(pData->hScroll, kControlPageDownPart);
  3634.                         else
  3635.                             HActionProc(pData->hScroll, kControlDownButtonPart);
  3636.                         passToObject = false;
  3637.                         }
  3638.                     break;
  3639.                     }
  3640.         
  3641.             if (passToObject)
  3642.                 anErr = (*(pData->pKeyEvent)) (pWindow, pData, pEvent, isMotionKey);
  3643.             else
  3644.                 {
  3645.                 if ( (pData->documentAcceptsText == false) && !( pEvent->modifiers & cmdKey ) && !(isMotionKey) )
  3646.                     anErr = eDocumentNotModifiable;
  3647.                 }
  3648.             }
  3649.  
  3650.         if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) )
  3651.             ConductErrorDialog(anErr, cTypingCommand, ok);
  3652.             
  3653.         } // (menuResult == 0)
  3654.     
  3655.         
  3656.     return anErr;
  3657.     
  3658. } // DoKeyEvent
  3659.  
  3660. // --------------------------------------------------------------------------------------------------------------
  3661. OSStatus DoAdjustCursor(WindowPtr pWindow, Point *where)
  3662. {
  3663.     OSStatus        anErr = noErr;
  3664.     Point        whereMouse;
  3665.     Boolean        didAdjust = false;
  3666.     
  3667.     if (where)
  3668.         whereMouse = *where;
  3669.         
  3670.     if (pWindow)
  3671.         {
  3672.         // not one of our windows?  don't do anything
  3673.         if (GetWindowKind(pWindow) != userKind)
  3674.             didAdjust = true;
  3675.             
  3676.         SetPortWindowPort (pWindow);
  3677.         
  3678.         if ( (!didAdjust) && (gMachineInfo.haveTSM) )
  3679.             {
  3680.             if (!where)
  3681.                 {
  3682.                 GetMouse(&whereMouse);
  3683.                 LocalToGlobal(&whereMouse);
  3684.                 }
  3685. #if !TARGET_CARBON // SetTSMCursor not needed (nor available) in Carbon (MG 6/9/99)
  3686.             if (SetTSMCursor(whereMouse))
  3687.                 didAdjust = true;
  3688. #endif
  3689.             }
  3690.             
  3691.         if (!didAdjust)
  3692.             {
  3693.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  3694.             RgnHandle        content = NewRgn();
  3695.             Point            globalMouse;
  3696.             
  3697.             SetEmptyRgn(gCursorRgn);
  3698.     
  3699.             if (!where)
  3700.                 GetMouse(&whereMouse);
  3701.             globalMouse = whereMouse;
  3702.             LocalToGlobal(&globalMouse);
  3703.             
  3704.             GetWindowRegion(pWindow, kWindowContentRgn, content);
  3705.             if ((pData) && (PtInRgn(globalMouse, content)) && (PtInRect(whereMouse, &pData->contentRect)))
  3706.                 {
  3707.                 Rect            tempRect;
  3708.                 
  3709.                 tempRect = pData->contentRect;
  3710.                 LocalToGlobal(&TopLeft(tempRect));
  3711.                 LocalToGlobal(&BotRight(tempRect));
  3712.                 RectRgn(gCursorRgn, &tempRect);
  3713.                 
  3714.                 if (pData->pAdjustCursor)
  3715.                     anErr = (*(pData->pAdjustCursor)) (pWindow, pData, &whereMouse, gCursorRgn);
  3716.                 }
  3717.             DisposeRgn(content);
  3718.             }
  3719.         else
  3720.             anErr = eActionAlreadyHandled;
  3721.         }
  3722.     
  3723.     // nobody set the cursor, we do it ourselves
  3724.     if (anErr != eActionAlreadyHandled) {
  3725.         Cursor arrow;
  3726.         SetCursor(GetQDGlobalsArrow(&arrow));
  3727.     }
  3728.         
  3729.     return anErr;
  3730.     
  3731. } // DoAdjustCursor
  3732.  
  3733. // --------------------------------------------------------------------------------------------------------------
  3734. static long DetermineWaitTime(WindowPtr pWindow)
  3735. {
  3736.     long    waitTime = kMaxWaitTime;
  3737.     
  3738.     while (pWindow)
  3739.         {
  3740.         long            newWaitTime;
  3741.         WindowDataPtr    pData = GetWindowInfo(pWindow);
  3742.         
  3743.         if ((pData) && (pData->pCalculateIdleTime))
  3744.             newWaitTime = (*(pData->pCalculateIdleTime)) (pWindow, pData);
  3745.         else
  3746.             newWaitTime = kMaxWaitTime;
  3747.         
  3748.         if (newWaitTime < waitTime)
  3749.             waitTime = newWaitTime;
  3750.             
  3751.         pWindow = GetNextWindow(pWindow);
  3752.         }
  3753.     
  3754.     return(waitTime);
  3755.     
  3756. } // DetermineWaitTime
  3757.  
  3758. // --------------------------------------------------------------------------------------------------------------
  3759. static OSStatus GetFinderProcess( ProcessSerialNumber * outPSN )
  3760. {
  3761.     ProcessInfoRec    processInfo;
  3762.     OSStatus            outStatus = noErr;
  3763.  
  3764.     outPSN->lowLongOfPSN = 0;
  3765.     outPSN->highLongOfPSN = kNoProcess;
  3766.     
  3767.     processInfo.processInfoLength = sizeof(ProcessInfoRec);
  3768.     processInfo.processName = nil;
  3769.     processInfo.processAppSpec = nil;
  3770.     
  3771.     while( outStatus == noErr )
  3772.     {
  3773.         outStatus = GetNextProcess( outPSN );
  3774.         
  3775.         if( outStatus == noErr )
  3776.         {
  3777.             outStatus = GetProcessInformation( outPSN, &processInfo );
  3778.             if(        (outStatus == noErr)
  3779.                 &&    (processInfo.processSignature == 'MACS')
  3780.                 &&    (processInfo.processType == 'FNDR') )
  3781.             {
  3782.                 break;
  3783.             }
  3784.         }
  3785.     }
  3786.     
  3787.     return outStatus;
  3788. }
  3789.  
  3790. static OSStatus BringFinderToFront(void)
  3791. {
  3792.     OSStatus                outStatus;
  3793.     ProcessSerialNumber        finderProcess;
  3794.     
  3795.     outStatus = GetFinderProcess( &finderProcess );
  3796.     if ( outStatus == noErr )
  3797.     {
  3798.         outStatus = SetFrontProcess( &finderProcess );
  3799.     }
  3800.     
  3801.     return outStatus;
  3802. }
  3803.  
  3804.  
  3805.  
  3806. void HandleNavUserAction( NavDialogRef inNavDialog, NavUserAction inUserAction, void *inContextData )
  3807. {
  3808.     OSStatus    status = noErr;
  3809.  
  3810.     // We only have to handle the user action if the context data is non-NULL, which
  3811.     // means it is an action that applies to a specific document.
  3812.     if ( inContextData != NULL )
  3813.     {
  3814.         // The context data is a window data pointer
  3815.         WindowDataPtr    pData = (WindowDataPtr)inContextData;
  3816.         Boolean            discard = false;
  3817.  
  3818.         // The dialog is going away, so clear the window's reference
  3819.         pData->navDialog = NULL;
  3820.  
  3821.         switch( inUserAction )
  3822.         {
  3823.             case kNavUserActionCancel:
  3824.             {
  3825.                 // If we were closing, we're not now.
  3826.                 pData->isClosing = false;
  3827.                 // If we were closing all, we're not now!
  3828.                 gMachineInfo.isClosing = false;
  3829.                 // If we were quitting, we're not now!!
  3830.                 gMachineInfo.isQuitting = false;
  3831.             }
  3832.             break;
  3833.             
  3834.             case kNavUserActionSaveChanges:
  3835.             {
  3836.                 // Do the save, which may or may not trigger the save dialog
  3837.                 status = DoCommand( pData->theWindow, cSave, 0, 0 );
  3838.             }
  3839.             break;
  3840.             
  3841.             case kNavUserActionDontSaveChanges:
  3842.             {
  3843.                 // OK to throw away this document
  3844.                 discard = true;
  3845.             }
  3846.             break;
  3847.             
  3848.             case kNavUserActionSaveAs:
  3849.             {
  3850.                 if ( pData->pSaveTo )
  3851.                 {
  3852.                     OSStatus        completeStatus;
  3853.                     NavReplyRecord     reply;
  3854.                     FSSpec            spec;
  3855.                     status = BeginSave( inNavDialog, &reply, &spec );
  3856.                     nrequire( status, BailSaveAs );
  3857.  
  3858.                     status = (*(pData->pSaveTo))( pData->theWindow, pData, &spec, reply.isStationery );
  3859.                     completeStatus = CompleteSave( &reply, &spec, status == noErr );
  3860.                     if ( status == noErr )
  3861.                     {
  3862.                         status = completeStatus;    // So it gets reported to user.
  3863.                     }
  3864.                     nrequire( status, BailSaveAs );
  3865.  
  3866.                     // Leave both forks open
  3867.                     if ( pData->dataRefNum == -1 )
  3868.                     {
  3869.                         status = FSpOpenDF( &spec, fsRdWrPerm, &pData->dataRefNum );
  3870.                         nrequire( status, BailSaveAs );
  3871.                     }
  3872.  
  3873.                     if ( pData->resRefNum == -1 )
  3874.                     {
  3875.                         pData->resRefNum = FSpOpenResFile( &spec, fsRdWrPerm );
  3876.                         status = ResError();
  3877.                         nrequire( status, BailSaveAs );
  3878.                     }
  3879.  
  3880.                 }
  3881.             }
  3882.         BailSaveAs:
  3883.             break;
  3884.         }
  3885.         
  3886.         // Now, close the window if it isClosing and
  3887.         // everything got clean or was discarded
  3888.         if ( status != noErr )
  3889.         {
  3890.             // Cancel all in-progress actions and alert user.
  3891.             pData->isClosing = false;
  3892.             gMachineInfo.isClosing = false;
  3893.             gMachineInfo.isQuitting = false;
  3894.             ConductErrorDialog( status, cSave, cancel );
  3895.         }
  3896.         else if ( pData->isClosing && ( discard || CanCloseWindow( pData->theWindow )))
  3897.         {
  3898.             status = DoCloseWindow( pData->theWindow, discard, 0 );
  3899.  
  3900.             // If we are closing all then start the close
  3901.             // process on the next window
  3902.             if ( status == noErr && gMachineInfo.isClosing )
  3903.             {
  3904.                 WindowPtr nextWindow = FrontWindow();
  3905.                 if ( nextWindow != NULL )
  3906.                 {
  3907.                     DoCloseWindow( nextWindow, false, 0 );
  3908.                 }
  3909.             }
  3910.         }
  3911.     }
  3912. }
  3913.  
  3914.  
  3915. void HandleEvent(EventRecord * pEvent)
  3916. {
  3917.     WindowPtr    pWindow;
  3918.     Boolean        handled;
  3919.     
  3920.     pWindow    = FrontWindow();
  3921.     handled    = false;
  3922.     
  3923.     switch (pEvent->what)
  3924.         {
  3925.         case kHighLevelEvent:
  3926.             AEProcessAppleEvent(pEvent);
  3927.             break;
  3928.             
  3929.         case osEvt:
  3930.             switch ((pEvent->message >> 24) & 0xFF) /* high byte of message */
  3931.                 {        
  3932.                 case mouseMovedMessage:
  3933.                     DoAdjustCursor(pWindow, nil);
  3934.                     break;
  3935.                     
  3936.                 case suspendResumeMessage:        /* suspend/resume is also an activate/deactivate */
  3937.                     gMachineInfo.amInBackground = (pEvent->message & 1) == 0;
  3938.                     if (pWindow)
  3939.                         DoActivate(pWindow, !gMachineInfo.amInBackground);
  3940.                     break;
  3941.                 }
  3942.             break;
  3943.             
  3944.         case activateEvt:
  3945.             pWindow = (WindowPtr) pEvent->message;
  3946.             DoActivate(pWindow, (pEvent->modifiers & activeFlag) != 0);
  3947.             break;
  3948.                             
  3949.         // disk inserted events must be handled, or uninitialized floppies 
  3950.         // won't be recognized.
  3951.         case diskEvt:
  3952.             if ( HiWord(pEvent->message) != noErr ) 
  3953.                 {
  3954.                 Point    where;
  3955.             
  3956.                 SetPt(&where, 70, 50);
  3957.                 ShowCursor();
  3958.             //    (void) DIBadMount(where, pEvent->message);
  3959.                 }        
  3960.             break;
  3961.                 
  3962.         case mouseUp:
  3963.             break;
  3964.             
  3965.         case mouseDown:
  3966.             {
  3967.             short part = FindWindow(pEvent->where, &pWindow);                    
  3968.             
  3969.             DoAdjustCursor(pWindow, &pEvent->where);
  3970.             switch ( part ) 
  3971.                 {
  3972.                 case inContent:
  3973.                     if (pWindow != FrontWindow())
  3974.                         SelectWindow(pWindow);
  3975.                     else
  3976.                         DoContentClick(pWindow);
  3977.                     break;
  3978.                     
  3979.                 case inGoAway:
  3980.                     if (TrackGoAway(pWindow, pEvent->where) )
  3981.                     {
  3982.                         //
  3983.                         // added option-close, because it’s in the HIG
  3984.                         //
  3985.                         if( pEvent->modifiers & optionKey )
  3986.                         {
  3987.                             // Close the clean documents, others will be confirmed one by one.
  3988.                             CloseAllWindows( false );                            
  3989.                         }
  3990.                         else
  3991.                         {
  3992.                             DoCommand(pWindow, cClose, 0, 0);
  3993.                         }
  3994.                     }
  3995.                     break;
  3996.                     
  3997.                 case inGrow:
  3998.                     DoGrowWindow(pWindow, pEvent);
  3999.                     break;
  4000.                     
  4001.                 case inZoomIn:
  4002.                 case inZoomOut:
  4003.                     if ( TrackBox(pWindow, pEvent->where, part) )
  4004.                         DoZoomWindow(pWindow, part);
  4005.                     break;
  4006.                     
  4007.                 case inProxyIcon:
  4008.                 //
  4009.                 // We’ve seen a hit in the window proxy, so drag the window proxy
  4010.                 //
  4011.                 // We should only be here on a machine with the native window manager
  4012.                 // but we still want to conditionalize it to be fully paraniod
  4013.                 //                
  4014. //                check(gMachineInfo.haveProxyIcons);
  4015.                 {
  4016.                     WindowDataPtr    pData = GetWindowInfo(pWindow);
  4017.                     
  4018.                     if( gMachineInfo.haveProxyIcons && (pData != NULL) )
  4019.                     {
  4020.                         OSStatus        status = TrackWindowProxyDrag( pWindow, pEvent->where );
  4021.                         
  4022.                         if( status == errUserWantsToDragWindow )
  4023.                             handled = false;
  4024.                         else if( status == noErr )
  4025.                             handled = true;
  4026.                     }
  4027.                 }
  4028.                 // fall through
  4029.                 case inDrag:
  4030.                     if( !handled )
  4031.                     {
  4032.                         WindowDataPtr    pData = GetWindowInfo(pWindow);
  4033.                     
  4034.                         //
  4035.                         // Show the file path select popup
  4036.                         //
  4037.                         if( gMachineInfo.haveProxyIcons && (pData != NULL) )
  4038.                         {
  4039.                             if( IsWindowPathSelectClick( pWindow, pEvent ) )
  4040.                             {
  4041.                                 SInt32 itemSelected;
  4042.                             
  4043.                                 if(WindowPathSelect( pWindow, NULL, &itemSelected ) == noErr )
  4044.                                 {
  4045.                                     // switch to the Finder, since the window probably isn’t visible.
  4046.                                     if( LoWord(itemSelected) > 1 )
  4047.                                     {
  4048.                                         BringFinderToFront();
  4049.                                     }
  4050.                                 }
  4051.                                 
  4052.                                 handled = true;
  4053.                             }
  4054.                         }
  4055.                         
  4056.                         if( !handled )
  4057.                         {
  4058.                             BitMap    screenBits;
  4059.                             
  4060.                             GetQDGlobalsScreenBits( &screenBits );
  4061. #if ALLOW_QUICKTIME
  4062.                             if ( (pData) && (pData->dragWindowAligned) )
  4063.                                 DragAlignedWindow((WindowPtr) pWindow, pEvent->where, &screenBits.bounds, nil, nil);
  4064.                             else
  4065.                                 DragWindow(pWindow, pEvent->where, &screenBits.bounds);
  4066. #else
  4067.  
  4068.                             DragWindow(pWindow, pEvent->where, &screenBits.bounds);
  4069.                         }
  4070.                                 
  4071. #endif
  4072.                     }
  4073.                     break;
  4074.                 
  4075.                 case inMenuBar:                /* process a mouse menu command (if any) */
  4076.                     {
  4077.                         long            menuResult;
  4078.                         WindowDataPtr    pData;
  4079.                         
  4080.                         // force these threads to run to completion so the
  4081.                         // contents of the menus are fully initialized
  4082.                         
  4083.                         if (gFontThread != kNoThreadID)
  4084.                         {
  4085.                             gDontYield = true;
  4086.                             SetThreadState(gFontThread, kReadyThreadState, gFontThread);
  4087.                             YieldToThread(gFontThread);
  4088.                             gDontYield = false;
  4089.                         }
  4090.                         
  4091.                         pWindow = FrontWindow();
  4092.                         pData = GetWindowInfo(pWindow);
  4093.                         if ((pData) && (pData->pPreMenuAccess))
  4094.                             (void) (*(pData->pPreMenuAccess)) (pWindow, pData);
  4095.                         AdjustMenus(pWindow, true, false);
  4096.                         InitCursor();
  4097.                         menuResult = MenuSelect(pEvent->where);
  4098.                         DoMenuCommand(pWindow, menuResult, 0);
  4099.                     }
  4100.                     break;
  4101.                     
  4102.                 } // switch(part)
  4103.             }
  4104.             break;
  4105.             
  4106.         case keyDown:
  4107.         case autoKey:                        /* check for menukey equivalents */
  4108.             DoKeyEvent(pWindow, pEvent, true);
  4109.             break;
  4110.             
  4111.         case updateEvt:
  4112.             pWindow = (WindowPtr) pEvent->message;
  4113.             (void) DoUpdateWindow(pWindow);
  4114.             break;
  4115.  
  4116.         } // switch (pEvent->what)
  4117.     
  4118. } // HandleEvent
  4119.  
  4120. // -----------------------------------------------------------------------------------------------------------
  4121. static void SynchronizeFiles( void )
  4122. {
  4123.     //
  4124.     // File synchronization for all document windows
  4125.     //
  4126.     static UInt32            nextSynchTicks = 10;
  4127.     UInt32                    currentTicks = TickCount();
  4128.     WindowPtr                currentWindow = FrontWindow();
  4129.     
  4130.     // only synchronize every so often...
  4131.     if( currentTicks > nextSynchTicks )
  4132.     {
  4133.         //
  4134.         // Loop over all our document windows,
  4135.         // searching for files whose locations have changed
  4136.         //
  4137.         while ( currentWindow != NULL )
  4138.         {
  4139.             WindowDataPtr    documentWindowData = GetWindowInfo(currentWindow);
  4140.             
  4141.             //
  4142.             // If it's a SimpleText-owned window and it has an associated file...
  4143.             //
  4144.             if( (documentWindowData != NULL)
  4145.                    && (documentWindowData->dataRefNum != -1) )
  4146.             {
  4147.                 Boolean        wasChanged = false;
  4148.                 FSSpec        newSpec;
  4149.                 FolderType    folder = 0;
  4150.                 
  4151.                 //
  4152.                 // Ask the Alias Manager where the window went
  4153.                 //
  4154.                 (void) ResolveAlias( NULL, documentWindowData->fileAlias, &newSpec, &wasChanged );
  4155.                 if( wasChanged )
  4156.                 {
  4157.                     //
  4158.                     // The file location has changed; update the window
  4159.                     //
  4160.                     documentWindowData->fileSpec = newSpec;
  4161.                     
  4162.                     // user might have renamed the file 
  4163.                     SetWTitle( currentWindow, newSpec.name );
  4164.                     
  4165.                     //
  4166.                     // Close the window if the user moved the Is it in the trash?
  4167.                     //
  4168.                     IdentifyFolder( newSpec.vRefNum, newSpec.parID, &folder );
  4169.                     
  4170.                     if( folder == kTrashFolderType )
  4171.                     {
  4172.                         DoCloseWindow( currentWindow, false, 0 );
  4173.                     }
  4174.                 }
  4175.             }
  4176.                 
  4177.             currentWindow = GetNextWindow( currentWindow );
  4178.         }
  4179.         
  4180.         //
  4181.         // To avoid flooding the CPU, wait at least one second
  4182.         // between file synch checks 
  4183.         //
  4184.         nextSynchTicks = ( currentTicks + 60 );
  4185.     }
  4186. }
  4187.  
  4188.  
  4189. static OSStatus    DoEventLoop(void)
  4190. {
  4191.     OSStatus    anErr = noErr;
  4192.     Boolean        gotEvent;
  4193.     Boolean        trueGotEvent;
  4194.     WindowPtr    pWindow;
  4195.     Boolean        over = false;
  4196.     do
  4197.     {
  4198.         Rect r;
  4199.         Point    pt;
  4200.  
  4201.         pWindow = GetWindowList();    // walk all of our windows, even invisible ones
  4202.  
  4203. #define kMaxWindows 256
  4204.     if (FrontWindow()) {
  4205.         SetPort(GetWindowPort(FrontWindow()));
  4206.         GetPortBounds(GetWindowPort(FrontWindow()), &r);
  4207.         r.left = r.right - 32;
  4208.         r.top = r.bottom - 32;
  4209.         GetMouse(&pt);
  4210.         
  4211.         if ((over && !PtInRect(pt, &r)) || (over == false && PtInRect(pt, &r))) {
  4212.             CGSConnectionID    connID = _CGSDefaultConnection();
  4213.             CGSConnectionID    myConnID = connID;
  4214.             CGSWindowCount    cnt;
  4215.             CGSWindowID    windows[kMaxWindows];
  4216.             CGSWindowID    lastWID;
  4217.             CGRect        rects[kMaxWindows];
  4218.             CGError        err;
  4219.             int        i;
  4220.             
  4221.         
  4222.             err = CGSGetOnScreenWindowList(myConnID, kCGSNullConnectionID, kMaxWindows, windows, &cnt);
  4223.         
  4224.             for (i = 0; i < cnt; i++) {
  4225.                 int width, height, top, left;
  4226.                 CGPoint    cgpt;
  4227.                 cgpt.x = 128.0;  cgpt.y = 128.0;
  4228.                 CGSGetScreenRectForWindow(myConnID, windows[i], &rects[i]);
  4229.                 top = (int)rects[i].origin.x;     left = (int)rects[i].origin.y;
  4230.                 width = (int)rects[i].size.width; height = (int)rects[i].size.height;
  4231.                 /* if (width == 24 && height == 24) */ {
  4232.                     cgpt.x = rects[i].origin.x;
  4233.                     cgpt.y = rects[i].origin.y - rects[i].size.height;
  4234.     //                CGSInvalidateWindowShadow(myConnID, windows[i]);
  4235.                     err = CGSGetWindowOwner(myConnID, windows[i], &connID);
  4236.     //                err = CGSSetWindowOwner(myConnID, windows[i], myConnID);
  4237.                     if (connID == myConnID)
  4238.     //                CGContextBeginContent(connID);
  4239.                     {
  4240.                         unsigned long delayLong;
  4241.                         cgpt.x = rects[i].origin.x + 2.0;
  4242.                         cgpt.y = rects[i].origin.y + 2.0;
  4243.                     //    err = CGSMoveWindow(connID , windows[i], &cgpt);
  4244.                         if (rects[i].origin.y + rects[i].size.height > 700) {
  4245.                             err = CGSSetWindowLevel(connID, windows[i], over ? kCGSNormalWindowLevel : kCGSDraggingWindowLevel);
  4246.                         }
  4247.     //                    Delay(5, &delayLong);
  4248.                     }
  4249.     //                CGContextEndContent(connID);
  4250.     //                if (lastWID) err = CGSOrderWindow(myConnID, windows[i], kCGSOrderBelow, lastWID);
  4251.                     lastWID = windows[i];
  4252.         //            err = CGSMoveWindowList(connID, 0, -24, &windows[i], 1);
  4253.     //                if (err == kCGErrorIllegalArgument) printf("(That would be kCGErrorIllegalArgument)");
  4254.     //                if (err == kCGErrorInvalidConnection) printf("(That would be kCGErrorInvalidConnection)");
  4255.     //                err = CGSSetWindowOwner(myConnID, windows[i], connID);
  4256.                 }
  4257.             }
  4258.             over = !over;
  4259.         }
  4260.     
  4261.     }
  4262.         
  4263.         /*
  4264.             We used to call DoAdjustCursor every time through the event loop, but that produced
  4265.             nasty cursor flickering when using the magic marker cursor over GX documents. We're
  4266.             now smarter and allow the adjustCursor callback to manipulate the cursor region.
  4267.             However, there may still be cases where the cursor doesn't get adjusted properly.
  4268.             If you suspect a cursor adjustment problem, try putting this call to DoAdjustCursor
  4269.             back in and see what the cursor does. Then fix the code to accurately maintain the
  4270.             cursor region and remove the DoAdjustCursor call. -ecs 11/25/96
  4271.         */
  4272.         // DoAdjustCursor(pWindow, nil);
  4273.         gotEvent = WaitNextEvent(everyEvent, &gEvent, DetermineWaitTime(pWindow), gCursorRgn);
  4274.         trueGotEvent = gotEvent;
  4275.  
  4276.         //
  4277.         // Synchronize all files on every event
  4278.         //
  4279.         SynchronizeFiles();
  4280.  
  4281.         // WNE may close the window if it's owned by some silly extension.
  4282.         pWindow = GetWindowList();        
  4283.         
  4284.         // let text services handle the event first if it wishes to do so
  4285.         if ( gMachineInfo.haveTSM )
  4286.             {
  4287.             ScriptCode    keyboardScript;
  4288.             WindowPtr    theFront = FrontWindow();
  4289.             
  4290.             if (theFront)
  4291.                 {
  4292.                 CGrafPtr fPort = GetWindowPort(theFront);
  4293.                 SetPort(fPort);
  4294.                 
  4295.                 keyboardScript = GetScriptManagerVariable(smKeyScript);
  4296.                                 if (FontToScript(GetPortTextFont(fPort)) != keyboardScript)
  4297.                     TextFont(GetScriptVariable(keyboardScript, smScriptAppFond));
  4298.                 }
  4299.             }
  4300.             
  4301.         // let all windows filter this event, and get time if they wish to
  4302.         while (pWindow)
  4303.             {
  4304.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  4305.             Boolean            finishedEvent = false;
  4306.                                 
  4307.             // if we hit a window we know about, then do filtering
  4308.             if (pData)
  4309.                 {
  4310.                 if (pData->pFilterEvent)
  4311.                     finishedEvent = (*(pData->pFilterEvent)) (pWindow, pData, &gEvent);
  4312.                 }
  4313.  
  4314.             // if filtering indicates complete handling of event, then stop, and
  4315.             // do no regular processing.
  4316.             if (finishedEvent)
  4317.                 {
  4318.                 gotEvent = false;
  4319.                 pWindow = nil;
  4320.                 }
  4321.             else
  4322.                 pWindow = GetNextWindow(pWindow);
  4323.             }
  4324.             
  4325.         if (gotEvent)
  4326.             HandleEvent(&gEvent);
  4327.             
  4328.         if ( gMachineInfo.isQuitting && FrontWindow() == NULL )
  4329.         {
  4330.             gAllDone = true;
  4331.         }
  4332.  
  4333.         // our threads are low-priority, so we only give time to them on idle
  4334.         if (gMachineInfo.haveThreads && !trueGotEvent && !gAllDone)
  4335.             YieldToAnyThread();
  4336.         
  4337.         } while (!gAllDone);
  4338.         
  4339.     return anErr;
  4340.     
  4341. } // DoEventLoop
  4342.  
  4343.  
  4344. //
  4345. // Close all windows
  4346. //
  4347. // Returns false to cancel
  4348. //
  4349. static Boolean CloseAllWindows( Boolean discard )
  4350. {
  4351.     WindowPtr    pWindow, nextWindow;
  4352.     WindowPtr    topClosingWindow = NULL;
  4353.  
  4354.     OSStatus    closeError = noErr;
  4355.     
  4356.     // Start the closing process by closing clean windows
  4357.     gMachineInfo.isClosing = true;
  4358.  
  4359.     // Close the open file dialog, if there is one.
  4360.     TerminateOpenFileDialog();
  4361.  
  4362.     // Close the clean windows, find the top one
  4363.     // that is already closing.
  4364.     pWindow = FrontWindow();
  4365.     while ( (pWindow != NULL) && closeError == noErr )
  4366.     {
  4367.         nextWindow = GetNextWindow(pWindow);
  4368.         if ( discard || CanCloseWindow( pWindow ))
  4369.         {
  4370.             closeError = DoCloseWindow( pWindow, discard, 0 );
  4371.         }
  4372.         else if ( topClosingWindow == NULL )
  4373.         {
  4374.             WindowDataPtr    pData = GetWindowInfo( pWindow );
  4375.             if ( pData && pData->isClosing )
  4376.             {
  4377.                 topClosingWindow = pWindow;
  4378.             }
  4379.         }
  4380.         pWindow = nextWindow;
  4381.     }
  4382.     
  4383.     // If there is a window that is already closing, bring it front.
  4384.     // Otherwise, start the close process on the front window.
  4385.     if ( topClosingWindow != NULL )
  4386.     {
  4387.         SelectWindow( topClosingWindow );
  4388.     }
  4389.     else if ( FrontWindow() != NULL )
  4390.     {
  4391.         DoCloseWindow( FrontWindow(), false, 0 );
  4392.     }
  4393.  
  4394.     return FrontWindow() == NULL;
  4395. }
  4396.  
  4397. // --------------------------------------------------------------------------------------------------------------
  4398. // DRAG MANAGEMENT GLOBAL SUPPORT ROUTINES
  4399. // --------------------------------------------------------------------------------------------------------------
  4400.  
  4401. // Globals for our drag handlers
  4402.  
  4403. Boolean                gCanAccept;                // if we can receive the item(s) being dragged
  4404.  
  4405. // --------------------------------------------------------------------------------------------------------------
  4406. static pascal OSErr GlobalTrackingHandler(short message, WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef)
  4407. {
  4408.     #pragma unused(handlerRefCon)
  4409.  
  4410.     WindowDataPtr pData = GetWindowInfo(pWindow);
  4411.  
  4412.     // Call the tracking handler associated with this type of window. Only allow messages referencing
  4413.     // a specific window to be passed to the handler.
  4414.  
  4415.     if (pData)
  4416.         {    
  4417.         if (pData->pDragTracking)
  4418.             return ((*(pData->pDragTracking)) (pWindow, pData, theDragRef, message));
  4419.         }
  4420.     
  4421.     return noErr;
  4422.  
  4423. } // GlobalTrackingHandler
  4424.  
  4425. DragTrackingHandlerUPP gGlobalTrackingHandler;
  4426.  
  4427. // --------------------------------------------------------------------------------------------------------------
  4428. static pascal OSErr GlobalReceiveHandler(WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef)
  4429. {
  4430.     #pragma unused(handlerRefCon)
  4431.  
  4432.     WindowDataPtr pData = GetWindowInfo(pWindow);
  4433.     
  4434.     if (pData)
  4435.         {
  4436.         if (pData->pDragTracking)
  4437.             return ((*(pData->pDragReceive)) (pWindow, pData, theDragRef));
  4438.         }
  4439.  
  4440.     return noErr;
  4441.  
  4442. } // GlobalReceiveHandler
  4443.  
  4444. DragReceiveHandlerUPP gGlobalReceiveHandler;
  4445.  
  4446. // --------------------------------------------------------------------------------------------------------------
  4447. //
  4448. // IsOnlyThisFlavor - Given a DragReference and a FlavorType, we iterate through the drag items to determine if
  4449. //                      all are of flavor theType. If this is so, we return true. If any of the items are not
  4450. //                      theType, we return false, indicating that we should not accept the drag.
  4451. //
  4452. Boolean IsOnlyThisFlavor(DragReference theDragRef, FlavorType theType)
  4453. {
  4454.     unsigned short    items, index;
  4455.     FlavorFlags        theFlags;
  4456.     ItemReference    itemID;
  4457.     OSStatus            anErr = noErr;
  4458.  
  4459.     CountDragItems(theDragRef, &items);
  4460.     
  4461.     for(index = 1; index <= items; index++)
  4462.         {
  4463.         GetDragItemReferenceNumber(theDragRef, index, &itemID);
  4464.  
  4465.         anErr = GetFlavorFlags(theDragRef, itemID, theType, &theFlags);
  4466.         if(anErr == noErr)
  4467.             continue;    // it's okay, this flavor is cool
  4468.  
  4469.         return false;    // this item has at least one flavor we don't like
  4470.         }
  4471.  
  4472.     return true;        // all flavors in this item were cool
  4473.  
  4474. } // IsOnlyThisFlavor
  4475.  
  4476. // --------------------------------------------------------------------------------------------------------------
  4477. //
  4478. // IsDropInFinderTrash - Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  4479. //
  4480. Boolean IsDropInFinderTrash(AEDesc *dropLocation)
  4481. {
  4482.     OSStatus            result;
  4483.     AEDesc            dropSpec;
  4484.     FSSpec            theSpec;
  4485.     CInfoPBRec        thePB;
  4486.     short            trashVRefNum;
  4487.     long            trashDirID;
  4488.  
  4489.     //    Coerce the dropLocation descriptor into an FSSpec. If there's no dropLocation or
  4490.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  4491.  
  4492.     if ((dropLocation->descriptorType != typeNull) &&
  4493.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) 
  4494.         {
  4495.         AEGetDescData(&dropSpec, &theSpec, sizeof(FSSpec) );
  4496.  
  4497.         //    Get the directory ID of the given dropLocation object.
  4498.  
  4499.         thePB.dirInfo.ioCompletion = 0L;
  4500.         thePB.dirInfo.ioNamePtr = (StringPtr) theSpec.name;
  4501.         thePB.dirInfo.ioVRefNum = theSpec.vRefNum;
  4502.         thePB.dirInfo.ioFDirIndex = 0;
  4503.         thePB.dirInfo.ioDrDirID = theSpec.parID;
  4504.  
  4505.         result = PBGetCatInfoSync(&thePB);
  4506.  
  4507.         AEDisposeDesc(&dropSpec);
  4508.  
  4509.         if (result != noErr)
  4510.             return false;
  4511.  
  4512.         //    If the result is not a directory, it must not be the Trash.
  4513.  
  4514.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  4515.             return false;
  4516.  
  4517.         //    Get information about the Trash folder.
  4518.  
  4519.         FindFolder(theSpec.vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  4520.  
  4521.         //    If the directory ID of the dropLocation object is the same as the directory ID
  4522.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  4523.  
  4524.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  4525.             return true;
  4526.         }
  4527.  
  4528.     return false;
  4529.  
  4530. } // IsDropInFinderTrash
  4531.  
  4532. // --------------------------------------------------------------------------------------------------------------
  4533. // APPLE EVENT SUPPORT ROUTINES
  4534. // --------------------------------------------------------------------------------------------------------------
  4535. static OSStatus    MissingParameterCheck(
  4536.     const AppleEvent     *inputEvent)
  4537. /*
  4538.     This routine checks an input AppleEvent for the missing keyword.
  4539.     If the missing keyword is found, that means that some required
  4540.     parameters were missing (ie, an error). 
  4541.     
  4542.     However, if the missing keyword isn't found, that means that we aren't missing 
  4543.     any required parameters (that is to say, all REQUIRED parameters were supplied
  4544.     by the person who created the event).
  4545.     
  4546.     SOME DAY, THE ABOVE COMMENT WILL MAKE SENSE TO YOU.  IT STILL DOESN'T
  4547.     TO ME AND I WAS THE ONE WHO WROTE IT.
  4548. */
  4549. {
  4550.     OSStatus        anErr;
  4551.     AEKeyword    missingKeyword;
  4552.     DescType    ignoredActualType;
  4553.     Size        ignoredActualSize;
  4554.     
  4555.     anErr = AEGetAttributePtr(
  4556.         inputEvent, 
  4557.         keyMissedKeywordAttr,
  4558.         typeWildCard,
  4559.         &ignoredActualType,
  4560.         (Ptr) &missingKeyword,
  4561.         sizeof(AEKeyword),
  4562.         &ignoredActualSize);
  4563.             
  4564.     if (anErr == noErr)
  4565.         anErr = errAEParamMissed;
  4566.     else
  4567.         if (anErr == errAEDescNotFound)
  4568.             anErr = noErr;
  4569.         
  4570.     return anErr;
  4571.     
  4572. } // MissingParameterCheck
  4573.  
  4574.  
  4575. // --------------------------------------------------------------------------------------------------------------
  4576. static pascal OSErr    DoOpenApp(
  4577.     const AppleEvent     *inputEvent,
  4578.     AppleEvent     *outputEvent,
  4579.     UInt32        handlerRefCon)
  4580. {
  4581. #pragma unused (outputEvent, handlerRefCon)
  4582.  
  4583.     DoCommand(nil, cNew, 0, 0);
  4584.     
  4585.     // so that the initial document opens more quickly, we don't start
  4586.     // the threads until we get an OpenApp or OpenDocument AppleEvent
  4587.     if (gStarterThread != kNoThreadID)
  4588.         SetThreadState(gStarterThread, kReadyThreadState, gStarterThread);
  4589.     
  4590.     return(MissingParameterCheck(inputEvent));
  4591.     
  4592. } // DoOpenApp
  4593.  
  4594. // --------------------------------------------------------------------------------------------------------------
  4595. static pascal OSErr    DoReopenApp(
  4596.     const AppleEvent     *inputEvent,
  4597.     AppleEvent     *outputEvent,
  4598.     UInt32        handlerRefCon)
  4599. {
  4600. #pragma unused (outputEvent, handlerRefCon)
  4601.  
  4602.     if (FrontWindow() == nil)
  4603.         DoCommand(nil, cNew, 0, 0);
  4604.     
  4605.     return(MissingParameterCheck(inputEvent));
  4606.     
  4607. } // DoReopenApp
  4608.  
  4609. // --------------------------------------------------------------------------------------------------------------
  4610. static pascal OSErr    DoQuitApp(
  4611.     const AppleEvent     *inputEvent,
  4612.     AppleEvent     *outputEvent,
  4613.     UInt32        handlerRefCon)
  4614. {
  4615. #pragma unused (outputEvent, handlerRefCon)
  4616.  
  4617.     DoCommand(nil, cQuit, 0, 0);
  4618.  
  4619.     return(MissingParameterCheck(inputEvent));
  4620.     
  4621. } // DoQuitApp
  4622.  
  4623. #if 0    // AEC, it does not appear this is ever called.  Do we need it?
  4624. WindowPtr OpenDoc(short DocKind, FSSpec *spec, StringPtr pass)
  4625. {       
  4626.     OSStatus    anErr;
  4627.     Boolean        wasAlreadyOpen;
  4628.     FInfo    theFileInfo; 
  4629.  
  4630.     anErr = FSpGetFInfo(spec, &theFileInfo);
  4631.     if (anErr == noErr)
  4632.         anErr = DetermineWindowTypeOrOpen(spec, theFileInfo.fdType, nil, nil, &wasAlreadyOpen);
  4633.  
  4634.     return(NULL);    // sorry, we won't tell you if it was successful
  4635. }
  4636. #endif // AEC
  4637.  
  4638. // --------------------------------------------------------------------------------------------------------------
  4639. // AEC, changed prototype to match headers
  4640. static pascal OSStatus    DoOpenOrPrint(
  4641.     const AppleEvent     *inputEvent,
  4642.     StringPtr    pPrinterName)    // nil == 0, zero length == print to default, other == printer name
  4643. {
  4644.  
  4645.     OSStatus        anErr, anErr2;
  4646.     AEDescList    docList;                // list of docs passed in
  4647.     long        index, itemsInList;
  4648.     Boolean        wasAlreadyOpen;
  4649.     
  4650.     anErr = AEGetParamDesc( inputEvent, keyDirectObject, typeAEList, &docList);
  4651.     nrequire(anErr, GetFileList);
  4652.  
  4653.     anErr = AECountItems( &docList, &itemsInList);            // how many files passed in
  4654.     nrequire(anErr, CountDocs);
  4655.     for (index = 1; index <= itemsInList; index++)            // handle each file passed in
  4656.         {    
  4657.         AEKeyword    keywd;
  4658.         DescType    returnedType;
  4659.         Size        actualSize;
  4660.         FSSpec        theFSS;    
  4661.  
  4662.         // Normally I would coerce here, but the coersion handles for
  4663.         // FSRef <-> FSSpec are not implemented yet.
  4664.         anErr = AEGetNthPtr( &docList, index, typeFSS, &keywd, &returnedType,    // get file's info
  4665.                             (Ptr)(&theFSS), sizeof(theFSS), &actualSize);
  4666.         if ( anErr == errAECoercionFail )
  4667.         {
  4668.             FSRef fileRef;
  4669.             anErr = AEGetNthPtr( &docList, index, typeFSRef, &keywd, &returnedType,
  4670.                             (Ptr)(&fileRef), sizeof( fileRef ), &actualSize );
  4671.             if ( anErr == noErr )
  4672.             {
  4673.                 anErr = FSGetCatalogInfo( &fileRef, kFSCatInfoNone, NULL, NULL, &theFSS, NULL );
  4674.             }
  4675.         }
  4676.         nrequire(anErr, AEGetNthPtr);
  4677.         
  4678.         {
  4679.         FInfo    theFileInfo;
  4680.         
  4681.         anErr = FSpGetFInfo(&theFSS, &theFileInfo);
  4682.         if (anErr == noErr)
  4683.             anErr = DetermineWindowTypeOrOpen(&theFSS, theFileInfo.fdType, nil, nil, &wasAlreadyOpen);
  4684.             
  4685.         if (anErr == eDocumentWrongKind)
  4686.             {
  4687.             if (pPrinterName)
  4688.                 ConductErrorDialog(anErr, cPrint, cancel);
  4689.             else
  4690.                 ConductErrorDialog(anErr, cOpen, cancel);
  4691.  
  4692.             anErr = noErr;
  4693.             break;
  4694.             }
  4695.             
  4696.         nrequire(anErr, DetermineWindowTypeOrOpen);
  4697.         }
  4698.         
  4699.         if (pPrinterName)
  4700.             {
  4701.             WindowPtr        pWindow = FrontWindow();
  4702.             WindowDataPtr    pData = GetWindowInfo(pWindow);
  4703.             
  4704.             if (pData->pPrintPage)
  4705.                 {
  4706.                 if (index == 1)
  4707.                     {
  4708.                         anErr = DoPrintSetup(pWindow, pPrinterName);
  4709.                     
  4710.                         if (anErr == noErr)
  4711.                         anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false);
  4712.                     }
  4713.                 }
  4714.             
  4715.             if (!wasAlreadyOpen)
  4716.                 DoCloseWindow(pWindow, false, 0);
  4717.  
  4718.             if (anErr != noErr)
  4719.                 break;
  4720.             }
  4721.         }
  4722.  
  4723.     // finally, make sure we didn't miss any parameters
  4724.     anErr2 = MissingParameterCheck(inputEvent);
  4725.     if (anErr == noErr)
  4726.         anErr = anErr2;
  4727.         
  4728. // FALL THROUGH EXCEPTION HANDLING
  4729. DetermineWindowTypeOrOpen:
  4730. AEGetNthPtr:
  4731. CountDocs:
  4732.     // done with doc list
  4733.     (void) AEDisposeDesc( &docList);                        
  4734.     
  4735. GetFileList:
  4736.  
  4737.     // don't report cancels from prints
  4738.     if (pPrinterName)
  4739.         {
  4740.         if (anErr == kPMCancel)
  4741.             anErr = noErr;
  4742.         }
  4743.     
  4744.     if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) )
  4745.         {
  4746.         if (pPrinterName)
  4747.             ConductErrorDialog(anErr, cPrint, cancel);
  4748.         else
  4749.             ConductErrorDialog(anErr, cOpen, cancel);
  4750.         }
  4751.         
  4752.     return anErr;
  4753.     
  4754. } // DoOpenOrPrint
  4755.  
  4756. // --------------------------------------------------------------------------------------------------------------
  4757. static pascal OSErr    DoOpenDocument(
  4758.     const AppleEvent     *inputEvent,
  4759.     AppleEvent     *outputEvent,
  4760.     UInt32        handlerRefCon)
  4761. {
  4762. #pragma unused (outputEvent, handlerRefCon)
  4763.  
  4764.     OSStatus        anErr;
  4765.     
  4766.     if (IsCommandEnabled(cOpen))
  4767.         {
  4768.         anErr = DoOpenOrPrint(inputEvent, nil);
  4769.         }
  4770.     else
  4771.         {
  4772.         anErr = errAEEventNotHandled;
  4773.         ConductErrorDialog(anErr, cOpen, cancel);
  4774.         }
  4775.         
  4776.     // so that the initial document opens more quickly, we don't start
  4777.     // the threads until we get an OpenApp or OpenDocument AppleEvent
  4778.     if (gStarterThread != kNoThreadID)
  4779.         SetThreadState(gStarterThread, kReadyThreadState, gStarterThread);
  4780.     
  4781.     return anErr;
  4782.     
  4783. } // DoOpenDocument
  4784.  
  4785. // --------------------------------------------------------------------------------------------------------------
  4786. static pascal OSErr    DoPrintDocument(
  4787.     const AppleEvent     *inputEvent,
  4788.     AppleEvent     *outputEvent,
  4789.     UInt32        handlerRefCon)
  4790. {
  4791. #pragma unused (outputEvent, handlerRefCon)
  4792.     OSStatus        anErr;
  4793.     FSSpec        printerFSS;
  4794.     AEDescList    dtpList;                // list of docs passed in
  4795.     
  4796.     if (IsCommandEnabled(cOpen))
  4797.         {
  4798.         // try to find out if this doc was dropped onto a printer
  4799.         anErr = AEGetAttributeDesc( inputEvent, keyOptionalKeywordAttr, typeAEList, &dtpList);
  4800.     
  4801.         if (anErr == noErr)                                            // doc dragged to dtp?
  4802.             {
  4803.             AEKeyword    keywd;
  4804.             DescType    returnedType;
  4805.             Size        actualSize;
  4806.     
  4807.             anErr = AEGetNthPtr( &dtpList, 1, typeFSS, &keywd, &returnedType,    // get dtp info
  4808.                             (Ptr)(&printerFSS), sizeof(printerFSS), &actualSize);
  4809.             }
  4810.             
  4811.         // if it wasn't, that's not an error, just print normally
  4812.         if (anErr != noErr)
  4813.             {
  4814.             printerFSS.name[0] = 0;
  4815.             anErr = noErr;
  4816.             }
  4817.             
  4818.         anErr = DoOpenOrPrint(inputEvent, &printerFSS.name[0]);
  4819.         }
  4820.     else
  4821.         {
  4822.         anErr = errAEEventNotHandled;
  4823.         ConductErrorDialog(anErr, cPrint, cancel);
  4824.         }
  4825.         
  4826.     return anErr;
  4827.     
  4828. } // DoPrintDocument
  4829.  
  4830.  
  4831. // --------------------------------------------------------------------------------------------------------------
  4832. // --------------------------------------------------------------------------------------------------------------
  4833. // MAIN INITIALIZE/SHUTDOWN/LOOP ROUTINES
  4834. // --------------------------------------------------------------------------------------------------------------
  4835. // --------------------------------------------------------------------------------------------------------------
  4836. // --------------------------------------------------------------------------------------------------------------
  4837. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4838. // while some other thread is running
  4839. // --------------------------------------------------------------------------------------------------------------
  4840. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4841. // while some other thread is running
  4842. #if 0
  4843. static long SortAndAddMenu(MenuHandle menu, Str255 newItem)
  4844. {
  4845.     short    numInMenu = CountMenuItems(menu);
  4846.     short    i;
  4847.     Str255    oldItem;
  4848.     
  4849.     for (i = 1; i <= numInMenu; ++i)
  4850.         {
  4851.         GetMenuItemText(menu, i, oldItem);
  4852.         switch(IUCompString(newItem, oldItem))
  4853.             {
  4854.             // already in?  Return index
  4855.             case 0:
  4856.                 return(i);
  4857.                 break;
  4858.                 
  4859.             // less than, keep scanning
  4860.             case 1:
  4861.                 break;
  4862.                 
  4863.             // greater than, add back one
  4864.             case -1:
  4865.                 InsertMenuItem(menu, "\pXXX", i-1);
  4866.                 SetMenuItemText(menu, i, newItem);
  4867.                 return(i);
  4868.                 break;
  4869.             }
  4870.         }
  4871.         
  4872.     // fall off the end?  add at the end
  4873.     InsertMenuItem(menu, "\pXXX", numInMenu);
  4874.     SetMenuItemText(menu, numInMenu+1, newItem);
  4875.             
  4876.     return(numInMenu+1);
  4877.     
  4878. } // SortAndAddMenu
  4879. #endif
  4880.  
  4881. // must be in Main because it runs in a thread and we don't want the segment unloaded
  4882. // while some other thread is running
  4883. static OSStatus BuildFontMenu(MenuHandle menu)
  4884. {
  4885.     OSStatus    anErr = noErr;
  4886.     
  4887.     AppendResMenu(menu, 'FONT');
  4888.     
  4889.     return(anErr);
  4890.     
  4891. } // BuildFontMenu
  4892.  
  4893. // --------------------------------------------------------------------------------------------------------------
  4894. // structures for FastGetNewMBar
  4895.  
  4896. typedef struct
  4897. {
  4898.     MenuHandle    menuOH;
  4899.     short        menuLeft;
  4900. }
  4901. MenuRec;
  4902.  
  4903. typedef struct
  4904. {
  4905.     short        lastMenu;
  4906.     short        lastRight;
  4907.     short        mbResID;
  4908.     MenuRec        menu[1];
  4909. }
  4910. DynamicMenuList;
  4911.  
  4912. // --------------------------------------------------------------------------------------------------------------
  4913. /*
  4914.     A much faster implementation of GetNewMBar, cuts about 0.3 second off the boot time on a 7500/100 running 7.5.5.
  4915.     
  4916.     DISABLED THIS CODE, APPLEGUIDE DEPENDS UPON INSERTMENU, WHICH THIS DOESN'T CALL.  STILL, THIS WOULD BE NICE
  4917.     TO DO AT SOME TIME!
  4918. */
  4919. #if 0
  4920. static Handle FastGetNewMBar(short id)
  4921. {
  4922.     Handle                hMbar;
  4923.     short                cMenus;
  4924.     int                    iMenu;
  4925.     MenuHandle            hmenu;
  4926.     DynamicMenuList**    hmenulist;
  4927.     
  4928.     hMbar = GetResource('MBAR', id);
  4929.     require(hMbar != NULL, GetResource);
  4930.     
  4931.     cMenus = *(short*) *hMbar;
  4932.     hmenulist = (DynamicMenuList**) NewHandleClear(sizeof(DynamicMenuList) + sizeof(MenuRec) * cMenus);
  4933.     require(hmenulist != NULL, NewMenuList);
  4934.         
  4935.     for (iMenu = 0; iMenu < cMenus; iMenu++)
  4936.         {
  4937.         hmenu = GetMenu(*(short*) ((BytePtr) *hMbar + 2 + 2 * iMenu));
  4938.         if (hmenu != NULL)
  4939.             (*hmenulist)->menu[iMenu].menuOH = hmenu;
  4940.         }
  4941.         
  4942.     ReleaseResource(hMbar);
  4943.     
  4944.     (*hmenulist)->lastMenu = cMenus * 6;
  4945.     return (Handle) hmenulist;
  4946.     
  4947.  
  4948. // EXCEPTION HANDLING
  4949. NewMenuList:
  4950.     ReleaseResource(hMbar);
  4951. GetResource:
  4952.  
  4953.     return NULL;
  4954.         
  4955. } // FastGetNewMBar
  4956. #endif
  4957.  
  4958. // --------------------------------------------------------------------------------------------------------------
  4959. static OSStatus    DoInitialize(void)
  4960. {
  4961. //    short                count;            // loop counter
  4962.     Handle                menuBar;        // for loading our menus in
  4963.     OSStatus        anErr = noErr;    // any errors we get, none so far
  4964.     long                version;        // version for Gestalt calls
  4965.  
  4966.     gMachineInfo.haveAppearanceMgr    = (Gestalt(gestaltAppearanceAttr, &version) == noErr) && ((version & (1<<gestaltAppearanceExists)) != 0);
  4967.     if (gMachineInfo.haveAppearanceMgr)
  4968.         RegisterAppearanceClient();
  4969.  
  4970.     //InitializeQTML( 0 );
  4971.     
  4972.     gAllDone = false;
  4973.     
  4974.     gMachineInfo.lastBalloonIndex = iNoBalloon;
  4975.     gMachineInfo.amInBackground = false;
  4976.     gMachineInfo.isQuitting = false;
  4977.     gMachineInfo.isClosing = false;
  4978.     gMachineInfo.documentCount  = 1;
  4979. #if ALLOW_QUICKTIME
  4980.     gMachineInfo.haveQuickTime     = (Gestalt(gestaltQuickTime, &version) == noErr);
  4981. #else
  4982.     gMachineInfo.haveQuickTime = false;
  4983. #endif
  4984.     gMachineInfo.haveRecording     = (Gestalt(gestaltSoundAttr, &version) == noErr) && ((version & (1<<gestaltHasSoundInputDevice)) != 0);
  4985. #if SPEECH_GESTALT_IMPLEMENTED
  4986.         gMachineInfo.haveTTS         = (Gestalt(gestaltSpeechAttr, &version) == noErr) && ((version & (1<<gestaltSpeechMgrPresent)) != 0);
  4987. #else
  4988.         gMachineInfo.haveTTS         = true; 
  4989. #endif
  4990.     gMachineInfo.haveTSM         = (Gestalt(gestaltTSMgrVersion, &version) == noErr) && (version >= 1);
  4991.     gMachineInfo.haveTSMTE         = (Gestalt(gestaltTSMTEAttr, &version) == noErr) && ((version & (1<<gestaltTSMTE)) != 0);
  4992.     gMachineInfo.haveDragMgr    = (Gestalt(gestaltDragMgrAttr, &version) == noErr) && ((version & (1<<gestaltDragMgrPresent)) != 0) &&
  4993.                                     (Gestalt(gestaltTEAttr, &version) == noErr) && ((version & (1<<gestaltTEHasGetHiliteRgn)) != 0);
  4994.     gMachineInfo.haveThreeD        = false;
  4995.     gMachineInfo.haveAppleGuide    = (Gestalt(gestaltHelpMgrAttr, &version) == noErr) && ((version & (1<<gestaltAppleGuidePresent)) != 0);
  4996.     gMachineInfo.haveThreads    = (Gestalt(gestaltThreadMgrAttr, &version) == noErr) && ((version & (1<<gestaltThreadMgrPresent)) != 0);
  4997.     
  4998.     gMachineInfo.haveNavigationServices  = NavServicesAvailable();
  4999.  
  5000.     //
  5001.     // Record the presence of >= 8.5 window manager features.
  5002.     //
  5003.     gMachineInfo.haveProxyIcons = false;
  5004.     gMachineInfo.haveFloatingWindows = false;
  5005.     
  5006. #if TARGET_CPU_PPC
  5007.  
  5008.     //
  5009.     if( ( Gestalt( gestaltWindowMgrAttr, &version ) == noErr ) )
  5010.     {
  5011.         if( version & (1L << gestaltWindowMgrPresentBit) )
  5012.         {
  5013.             gMachineInfo.haveProxyIcons = true;
  5014.         
  5015.             if( version & (1L << gestaltHasFloatingWindows) )
  5016.                 gMachineInfo.haveFloatingWindows = true;
  5017.         }
  5018.     }
  5019. #endif
  5020.  
  5021.  
  5022.     // initialize text services if they exist
  5023.     if (gMachineInfo.haveTSMTE)
  5024.         {
  5025. #if !TARGET_CARBON // InitTSMAwareApplication not needed (nor available) in Carbon (MG 6/9/99)
  5026.         if (InitTSMAwareApplication() != noErr)
  5027.             {
  5028.             gMachineInfo.haveTSM = false;
  5029.             gMachineInfo.haveTSMTE = false;
  5030.             }
  5031. #endif
  5032.         }
  5033.         
  5034.     // save away info we need from the get-go    
  5035.     gApplicationResFile = CurResFile();
  5036.     gCursorRgn = NewRgn();
  5037.  
  5038.     // load up the menus
  5039.     menuBar = (Handle) GetNewMBar(rMenuBar);    /* read menus into menu bar */
  5040.     anErr = ResError();
  5041.     if ( (anErr == noErr) && (menuBar == nil) )
  5042.         anErr = resNotFound;
  5043.     nrequire(anErr, GetNewMBar);
  5044.     
  5045.     // install menus
  5046.     SetMenuBar(menuBar);    
  5047.     DisposeHandle(menuBar);
  5048.  
  5049.     // Build the font menu
  5050.     anErr = BuildFontMenu(GetMenuHandle(mFont));
  5051.     nrequire(anErr, BuildFontMenu);
  5052.     
  5053.     // insert our heirarchical menus
  5054.     {
  5055.     MenuHandle     menu = MacGetMenu( mVoices );
  5056.     short        menuID, itemID;
  5057.     
  5058.     InsertMenu( menu, hierMenu );
  5059.     
  5060.     CommandToIDs(cSelectVoice, &menuID, &itemID);
  5061.     menu = GetMenuHandle(menuID);
  5062.  
  5063.     SetItemCmd( menu, itemID, hMenuCmd );
  5064.     SetItemMark( menu, itemID, mVoices );
  5065.     }
  5066.  
  5067.     (void) AdjustMenus(nil, true, false);
  5068.     
  5069.     // start up QuickTime, but problems result in us pretending not to have it
  5070. #if ALLOW_QUICKTIME
  5071.     if (gMachineInfo.haveQuickTime)
  5072.         if (EnterMovies() != noErr)
  5073.             gMachineInfo.haveQuickTime = false;
  5074. #endif
  5075.         
  5076.     // Install AppleEvent handlers for the base classes
  5077.  
  5078.     #define INSTALL(event, handler) \
  5079.             AEInstallEventHandler(kCoreEventClass, event, handler, 0, false)
  5080.     // AEC, changed to use the correct handler procs
  5081.     INSTALL (kAEOpenApplication, NewAEEventHandlerUPP(DoOpenApp));
  5082.     INSTALL ('rapp', NewAEEventHandlerUPP(DoReopenApp));
  5083.     INSTALL (kAEQuitApplication, NewAEEventHandlerUPP(DoQuitApp));
  5084.     INSTALL (kAEOpenDocuments,   NewAEEventHandlerUPP(DoOpenDocument));
  5085.     INSTALL (kAEPrintDocuments,  NewAEEventHandlerUPP(DoPrintDocument));
  5086.  
  5087.     #undef INSTALL
  5088.     
  5089.     // AEC, added control procs
  5090.     gVActionProc = NewControlActionUPP(VActionProc);
  5091.     gHActionProc = NewControlActionUPP(HActionProc);
  5092.  
  5093.  
  5094.     // Install our global dragging procs, but only if we have Drag and Drop. An error results
  5095.     // in us pretending that we don't have drag support. Notice that in the test above, we also
  5096.     // require TextEdit to have TEGetHiliteRgn avalilable, which is always the case with the
  5097.     // present Drag Manager.
  5098.  
  5099.     if (gMachineInfo.haveDragMgr)
  5100.         {
  5101.         gGlobalTrackingHandler = NewDragTrackingHandlerUPP(GlobalTrackingHandler);
  5102.         gGlobalReceiveHandler = NewDragReceiveHandlerUPP(GlobalReceiveHandler);
  5103.         
  5104.         anErr = InstallTrackingHandler(gGlobalTrackingHandler, nil, nil);
  5105.  
  5106.         if (anErr == noErr)
  5107.             {
  5108.             anErr = InstallReceiveHandler(gGlobalReceiveHandler, nil, nil);
  5109.  
  5110.             if (anErr != noErr)
  5111.                 {
  5112.                 RemoveTrackingHandler(gGlobalTrackingHandler, nil);
  5113.                 gMachineInfo.haveDragMgr = false;
  5114.                 }
  5115.             }
  5116.         else
  5117.             gMachineInfo.haveDragMgr = false;
  5118.         }
  5119.  
  5120.     // for AppleScript
  5121.     anErr = OpenADefaultComponent(kOSAComponentType, kOSAGenericScriptingComponentSubtype, &gOSAComponent);
  5122.  
  5123.     return noErr;
  5124.     
  5125.     
  5126. // EXCEPTION HANDLING
  5127. BuildFontMenu:
  5128. GetNewMBar:
  5129. // SysEnvirons:
  5130.     ConductErrorDialog(anErr, cNull, cancel);
  5131.     
  5132.     return anErr;
  5133.  
  5134. } // DoInitialize
  5135.  
  5136. // --------------------------------------------------------------------------------------------------------------
  5137. static OSStatus    DoTerminate(void)
  5138. {
  5139.     OSStatus    anErr = noErr;
  5140.     
  5141.     if (gFontThread != kNoThreadID)
  5142.         DisposeThread(gFontThread, &gThreadResults, false);
  5143.     if (gStarterThread != kNoThreadID)
  5144.         DisposeThread(gStarterThread, &gThreadResults, false);
  5145.  
  5146. #if ALLOW_QUICKTIME
  5147.     if (gMachineInfo.haveQuickTime)
  5148.         ExitMovies();
  5149. #endif
  5150.         
  5151. #if !TARGET_CARBON // CloseTSMAwareApplication not needed (nor available) in Carbon (MG 6/9/99)
  5152.     if (gMachineInfo.haveTSMTE)
  5153.         CloseTSMAwareApplication();
  5154. #endif
  5155.  
  5156.     if (gMachineInfo.haveDragMgr)
  5157.         {
  5158.         RemoveReceiveHandler(gGlobalReceiveHandler, nil);
  5159.         RemoveTrackingHandler(gGlobalTrackingHandler, nil);
  5160.         }
  5161.  
  5162.     if (gMachineInfo.haveAppearanceMgr)
  5163.         UnregisterAppearanceClient();
  5164.         
  5165.     // for AppleScript
  5166.     if (gOSAComponent)
  5167.         CloseComponent(gOSAComponent);
  5168.  
  5169.     return anErr;
  5170.     
  5171. } // DoTerminate
  5172.  
  5173. // --------------------------------------------------------------------------------------------------------------
  5174. int main (int argc, char **argv)
  5175. {
  5176.     OSStatus    anErr;
  5177.     
  5178. #if !defined( __MWERKS__ ) && !TARGET_CARBON
  5179.     UnloadSeg((Ptr) _DataInit);                        /* note that _DataInit must not be in Main! */
  5180. #endif
  5181.  
  5182.     MoreMasterPointers (0x40 * 3); /* we love handles */
  5183.  
  5184. #ifdef __MWERKS__
  5185. #if __option(profile)
  5186.     ProfilerInit(collectSummary, bestTimeBase, 500, 10);
  5187. #endif
  5188.  
  5189. #endif
  5190.     InitCursor(); // ••• hack to load carbon so our Gestalt calls will work
  5191.     {
  5192.         SInt32    metricSize;
  5193.         GetThemeMetric( kThemeMetricScrollBarWidth, &metricSize );
  5194.         kScrollBarSize = metricSize - 1;
  5195.     }
  5196.     anErr = DoInitialize();
  5197. #ifdef __MWERKS__
  5198. #if __option(profile)
  5199.     ProfilerDump("\pboot.prof");
  5200.     ProfilerSetStatus(false);
  5201.     ProfilerClear();
  5202. #endif
  5203. #endif
  5204.  
  5205.     if (anErr == noErr)
  5206.         {
  5207.         DoEventLoop();
  5208.  
  5209. #ifdef __MWERKS__
  5210. #if __option(profile)
  5211.         ProfilerTerm();
  5212. #endif
  5213. #endif
  5214.  
  5215. // REVIEW: don't want to unload the segment we're in!!
  5216. //        UnloadSeg((Ptr) DoEventLoop);
  5217.         DoTerminate();                    
  5218.         }
  5219.  
  5220.     return 0;
  5221. } // main
  5222.